From 8fdff5af690af5f91925ad63c74445349666376e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 04:15:45 +0000 Subject: [PATCH 001/293] chore(deps): update module github.com/golangci/golangci-lint to v1.60.1 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7732fbc244..55ace4eba2 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/master/install.sh | sh -s -- -b $(GOBIN) v1.60.1 .PHONY: tools tools: $(GOBIN)/golangci-lint From ef35d523671c520e926ad17512e4483a500ddf2e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 13 Aug 2024 18:41:09 +0100 Subject: [PATCH 002/293] build: validate against Go 1.23 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now it's released 🚀 --- .github/workflows/ci.yml | 1 + .github/workflows/generate.yml | 1 + .github/workflows/lint.yml | 1 + .github/workflows/tidy.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46a81612c6..0d44cd3411 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: - "1.20" - "1.21" - "1.22" + - "1.23" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index a05186cd50..e9e3ecbd4a 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -12,6 +12,7 @@ jobs: - "1.20" - "1.21" - "1.22" + - "1.23" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f560f5e6e4..9d4ae76a52 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,6 +12,7 @@ jobs: - "1.20" - "1.21" - "1.22" + - "1.23" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 687320a100..405e8aefec 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -12,6 +12,7 @@ jobs: - "1.20" - "1.21" - "1.22" + - "1.23" steps: - name: Check out source code uses: actions/checkout@v4 From f77bd7b1b84a7f215eb43d4cecc1ba10927326ef Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 16 Aug 2024 09:52:10 +0100 Subject: [PATCH 003/293] build: require Go 1.21 to build As part of future changes, we want to introduce a dependency on a library that requires Go 1.21, therefore we can preemptively bump the requirement. This also is not too controversial a requirement, as Go 1.21 has just gone end-of-life, so consumers are ideally on Go 1.22, the minimum supported Go version. We make sure to pin to the latest patch release of Go 1.21. --- .github/workflows/ci.yml | 1 - .github/workflows/generate.yml | 1 - .github/workflows/lint.yml | 1 - .github/workflows/tidy.yml | 1 - examples/go.mod | 2 +- examples/go.sum | 25 +++++++++++++++++++++++++ go.mod | 2 +- go.sum | 6 ++++++ internal/test/go.mod | 2 +- internal/test/go.sum | 25 +++++++++++++++++++++++++ 10 files changed, 59 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d44cd3411..76ce74f913 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,6 @@ jobs: # 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" - "1.23" diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index e9e3ecbd4a..912040ed14 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -9,7 +9,6 @@ jobs: # 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" - "1.23" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9d4ae76a52..4b27e4c7c5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,6 @@ jobs: # 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" - "1.23" diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 405e8aefec..3fa0173d2a 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -9,7 +9,6 @@ jobs: # 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" - "1.23" diff --git a/examples/go.mod b/examples/go.mod index 922b6db6cd..701f03cd32 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.20 +go 1.21.13 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ diff --git a/examples/go.sum b/examples/go.sum index 3ecc5f9e88..a08e123588 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -12,6 +12,7 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= @@ -34,6 +35,7 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPc 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/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= @@ -53,6 +55,7 @@ github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kO 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-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= @@ -60,7 +63,9 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 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-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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= @@ -72,7 +77,9 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW 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/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -81,10 +88,13 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl 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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= 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/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= @@ -111,9 +121,11 @@ github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuV 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/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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= @@ -147,6 +159,7 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/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= @@ -181,12 +194,15 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ 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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= @@ -227,13 +243,19 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/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/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.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= @@ -268,6 +290,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ 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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -313,6 +336,7 @@ google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -321,5 +345,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C 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= +moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/go.mod b/go.mod index f3acdd1612..f1a00e5b30 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.20 +go 1.21.13 require ( github.com/getkin/kin-openapi v0.126.0 diff --git a/go.sum b/go.sum index d932d898bd..b4c574d348 100644 --- a/go.sum +++ b/go.sum @@ -7,12 +7,15 @@ github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kO 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= @@ -22,6 +25,7 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V 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= @@ -29,12 +33,14 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index ebc261e697..68ad2ece30 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.20 +go 1.21.13 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ diff --git a/internal/test/go.sum b/internal/test/go.sum index 030525494c..a96e0371a0 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -12,6 +12,7 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= @@ -33,6 +34,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/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= @@ -52,6 +54,7 @@ github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kO 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-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= @@ -59,7 +62,9 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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= @@ -73,7 +78,9 @@ github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tb github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= 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/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= @@ -82,10 +89,13 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl 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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= 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/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= @@ -112,9 +122,11 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q 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/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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= @@ -137,6 +149,7 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/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= @@ -161,12 +174,15 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ 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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= @@ -210,13 +226,19 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/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/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.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= @@ -237,6 +259,7 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -274,6 +297,7 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -283,5 +307,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C 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= +moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From fa048ac69eeabb044f9bdf92c3870b9cb4e882c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:54:39 +0000 Subject: [PATCH 004/293] fix(deps): update module github.com/getkin/kin-openapi to v0.127.0 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 4 ++-- examples/go.mod | 2 +- examples/go.sum | 4 ++-- examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 9c835ddfaf..af155131b1 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.126.0 + github.com/getkin/kin-openapi v0.127.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 diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index fdfd5b7273..95a47863ff 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -4,8 +4,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/go.mod b/examples/go.mod index 701f03cd32..4a7845f7c2 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.21.13 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.126.0 + github.com/getkin/kin-openapi v0.127.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 diff --git a/examples/go.sum b/examples/go.sum index a08e123588..3d26ec2bf3 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -42,8 +42,8 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 03570cb92c..250b554dcd 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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/getkin/kin-openapi v0.127.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 diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index b4c574d348..0dd7f71102 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -1,7 +1,7 @@ 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 77f95539f5..6b542a4ae8 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.126.0 + github.com/getkin/kin-openapi v0.127.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 diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 1527625659..f104d6071b 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -5,8 +5,8 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/go.mod b/go.mod index f1a00e5b30..646b068927 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.21.13 require ( - github.com/getkin/kin-openapi v0.126.0 + github.com/getkin/kin-openapi v0.127.0 github.com/stretchr/testify v1.9.0 golang.org/x/text v0.15.0 golang.org/x/tools v0.21.0 diff --git a/go.sum b/go.sum index b4c574d348..0dd7f71102 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 68ad2ece30..96db19989a 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.21.13 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.126.0 + github.com/getkin/kin-openapi v0.127.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 diff --git a/internal/test/go.sum b/internal/test/go.sum index a96e0371a0..088b467c7a 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -41,8 +41,8 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 2e90c73f62..91505c2b67 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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/getkin/kin-openapi v0.127.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 diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index b1563e235e..dce56838d1 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -5,8 +5,8 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF 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/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= +github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= From 3cf49e0f881af6a20d7d0076e8e52fc1e02575c1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 16 Aug 2024 10:58:33 +0100 Subject: [PATCH 005/293] feat: add support for OpenAPI Overlay In the past, 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) 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. With these changes, 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[0], which is a stable specification, and is ready for wider implementation. This uses Speakeasy's implementation, which is noted as an "alpha" implementation. We introduce a new function, `LoadSwaggerWithOverlay`, which performs the wrangling of the Overlay on top of the specification we're pointing to, and make sure we wire in the ability to configure the path, as well as whether we want to relax the "strict" validation the Overlay library provides. Closes #1553. [0]: https://github.com/OAI/Overlay-Specification --- cmd/oapi-codegen/oapi-codegen.go | 12 +- configuration-schema.json | 18 +++ examples/authenticated-api/stdhttp/go.mod | 3 + examples/authenticated-api/stdhttp/go.sum | 104 ++++++++++++++++++ examples/go.mod | 3 + examples/go.sum | 92 +++++++++++++++- examples/minimal-server/stdhttp/go.mod | 3 + examples/minimal-server/stdhttp/go.sum | 121 +++++++++++++++++++++ examples/petstore-expanded/stdhttp/go.mod | 3 + examples/petstore-expanded/stdhttp/go.sum | 119 ++++++++++++++++++++ go.mod | 5 +- go.sum | 121 +++++++++++++++++++++ internal/test/go.mod | 3 + internal/test/go.sum | 91 +++++++++++++++- internal/test/strict-server/stdhttp/go.mod | 3 + internal/test/strict-server/stdhttp/go.sum | 119 ++++++++++++++++++++ pkg/codegen/configuration.go | 11 ++ pkg/util/loader.go | 67 ++++++++++++ 18 files changed, 892 insertions(+), 6 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 22e147c6de..1d166f8ba6 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -281,7 +281,17 @@ func main() { 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) } diff --git a/configuration-schema.json b/configuration-schema.json index 836d48ad61..6344cba2b8 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -196,6 +196,24 @@ "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" + ] } } }, diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index af155131b1..4a92656040 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -16,6 +16,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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 @@ -32,6 +33,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 95a47863ff..b0ae29103e 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -1,27 +1,58 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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/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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= @@ -41,10 +72,26 @@ 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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -53,10 +100,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb 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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= 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.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.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= @@ -65,37 +118,66 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT 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/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= 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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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.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/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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-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-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.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/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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= @@ -104,6 +186,7 @@ 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.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= @@ -112,16 +195,37 @@ 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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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= +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/examples/go.mod b/examples/go.mod index 4a7845f7c2..c1df048441 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -41,6 +41,7 @@ require ( 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/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 @@ -90,6 +91,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/tdewolff/minify/v2 v2.12.9 // indirect github.com/tdewolff/parse/v2 v2.6.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect @@ -100,6 +102,7 @@ require ( github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/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 diff --git a/examples/go.sum b/examples/go.sum index 3d26ec2bf3..5fd02f0c22 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -24,6 +24,9 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc 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/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/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= @@ -34,12 +37,19 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/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/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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= @@ -62,6 +72,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -72,15 +83,29 @@ github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84Egg 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/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 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.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/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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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= @@ -89,6 +114,8 @@ 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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= @@ -120,6 +147,7 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 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/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= @@ -168,6 +196,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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= @@ -182,6 +213,19 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW 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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -201,10 +245,12 @@ github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQ github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= 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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= 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= @@ -212,6 +258,8 @@ 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.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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -242,6 +290,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/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= @@ -256,6 +306,7 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO 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= @@ -263,6 +314,7 @@ golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 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/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= @@ -270,34 +322,51 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.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/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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/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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-20211216021012-1d35b9e2eb4e/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= @@ -323,6 +392,7 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= @@ -330,17 +400,35 @@ 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= 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= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 250b554dcd..829ac139b3 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -7,6 +7,7 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 require ( + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/getkin/kin-openapi v0.127.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect @@ -15,6 +16,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 0dd7f71102..2e22e64369 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -1,47 +1,168 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/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/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.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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +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.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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/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.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= +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/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 6b542a4ae8..14d2bc2594 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -16,6 +16,7 @@ require ( require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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 @@ -26,6 +27,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index f104d6071b..1ae6d4cb35 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -2,65 +2,184 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz 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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/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/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/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/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.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/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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= 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.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.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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/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.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= +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/go.mod b/go.mod index 646b068927..89d52354d8 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,17 @@ go 1.21.13 require ( github.com/getkin/kin-openapi v0.127.0 + github.com/speakeasy-api/openapi-overlay v0.9.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 + gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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 @@ -21,6 +24,6 @@ require ( 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 + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0dd7f71102..2e22e64369 100644 --- a/go.sum +++ b/go.sum @@ -1,47 +1,168 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/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/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.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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +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.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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/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.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= +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/go.mod b/internal/test/go.mod index 96db19989a..6cd91ad290 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -33,6 +33,7 @@ require ( 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/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 @@ -77,6 +78,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.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 @@ -88,6 +90,7 @@ require ( github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 088b467c7a..c020fc1083 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -30,15 +30,25 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ 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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= @@ -61,6 +71,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -71,17 +82,29 @@ github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbId 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/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 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.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/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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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= @@ -90,6 +113,8 @@ 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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= @@ -121,6 +146,7 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 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/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= @@ -158,12 +184,28 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -181,10 +223,12 @@ github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQ github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= 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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= 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= @@ -193,6 +237,8 @@ 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.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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -225,6 +271,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/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= @@ -239,43 +287,65 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO 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= 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/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +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/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.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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/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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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/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= @@ -284,6 +354,7 @@ 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/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= @@ -291,17 +362,33 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 91505c2b67..6887d5baa5 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -18,6 +18,7 @@ require ( require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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 @@ -27,6 +28,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index dce56838d1..711491dfe6 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -2,61 +2,180 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz 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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/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/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/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/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.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/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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= 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.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.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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/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.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= +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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index b9d8bad1d9..d60eb5ed8b 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -236,8 +236,19 @@ type OutputOptions struct { // 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"` } func (oo OutputOptions) Validate() map[string]string { return 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/util/loader.go b/pkg/util/loader.go index f29a160d7f..b10e594304 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -1,9 +1,14 @@ package util import ( + "bytes" + "fmt" "net/url" + "strings" "github.com/getkin/kin-openapi/openapi3" + "github.com/speakeasy-api/openapi-overlay/pkg/loader" + "gopkg.in/yaml.v3" ) func LoadSwagger(filePath string) (swagger *openapi3.T, err error) { @@ -25,3 +30,65 @@ 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 + data, err := yaml.Marshal(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(bytes.NewReader(data)).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 { + err, vs := 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) + } + + swagger, err = openapi3.NewLoader().LoadFromData(b) + if err != nil { + return nil, fmt.Errorf("Failed to serialize Overlay'd specification %#v: %v", opts.Path, err) + } + + return swagger, nil +} From c66e13a61015f0531253a3d277aa8094a1dae23d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 16 Aug 2024 10:58:52 +0100 Subject: [PATCH 006/293] docs(examples): add example for Overlay usage As part of #1553. This tries to cover a lot of the more complex cases. Plus a fair bit of blurb + info to the README too. --- README.md | 85 ++++++++++ examples/overlay/api/api.yaml | 91 +++++++++++ examples/overlay/api/cfg.yaml | 10 ++ examples/overlay/api/generate.go | 3 + examples/overlay/api/impl.go | 25 +++ examples/overlay/api/overlay.yaml | 53 +++++++ examples/overlay/api/ping.gen.go | 256 ++++++++++++++++++++++++++++++ examples/overlay/main.go | 27 ++++ 8 files changed, 550 insertions(+) create mode 100644 examples/overlay/api/api.yaml create mode 100644 examples/overlay/api/cfg.yaml create mode 100644 examples/overlay/api/generate.go create mode 100644 examples/overlay/api/impl.go create mode 100644 examples/overlay/api/overlay.yaml create mode 100644 examples/overlay/api/ping.gen.go create mode 100644 examples/overlay/main.go diff --git a/README.md b/README.md index 38d6671ce1..07857cbcb3 100644 --- a/README.md +++ b/README.md @@ -1947,6 +1947,91 @@ If you don't want to do this, an alternate option is to [bundle your multiple Op Check out [the import-mapping example](examples/import-mapping/) for the full code. +## Modifying the input OpenAPI Specification + +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: $.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/deepmap/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 overlay example](examples/overlay/) for the full code, and some more complex examples. + ## Generating Nullable types It's possible that you want to be able to determine whether a field isn't sent, is sent as `null` or has a value. diff --git a/examples/overlay/api/api.yaml b/examples/overlay/api/api.yaml new file mode 100644 index 0000000000..367ffb19e8 --- /dev/null +++ b/examples/overlay/api/api.yaml @@ -0,0 +1,91 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)" +paths: + /ping: + get: + responses: + '200': + description: pet response + content: + application/json: + schema: + $ref: '#/components/schemas/Pong' + delete: + x-internal: true + responses: + '202': + content: {} + /admin/autoscaling: + get: + # this is a method-level `tags` + tags: + - internal + responses: + '200': + content: + application/json: + schema: + type: object + properties: + instances: + type: number + required: + - instances + /healthz: + x-internal: true + get: + responses: + '200': + content: {} + /admin/users/reset-password: + x-internal: true + put: + requestBody: + content: + application/json: + schema: + type: object + properties: + username: + type: string + not_documented: + type: string + format: uuid + x-internal: true + required: + - username + responses: + '200': + content: + application/json: + schema: + type: object + properties: + password: + type: string + not_documented: + type: string + format: uuid + x-internal: true + required: + - password +components: + schemas: + # base types + Pong: + type: object + required: + - ping + properties: + ping: + type: string + example: pong + seed: + type: number + description: The seed for the internal randomness. SHOULD NOT be explained to users + # undocumented and not useful + verbose: + type: boolean + x-internal: true diff --git a/examples/overlay/api/cfg.yaml b/examples/overlay/api/cfg.yaml new file mode 100644 index 0000000000..b506fc5679 --- /dev/null +++ b/examples/overlay/api/cfg.yaml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=../../../configuration-schema.json +package: api +output: ping.gen.go +generate: + models: true + gorilla-server: true + embedded-spec: true +output-options: + overlay: + path: overlay.yaml diff --git a/examples/overlay/api/generate.go b/examples/overlay/api/generate.go new file mode 100644 index 0000000000..c025a4570d --- /dev/null +++ b/examples/overlay/api/generate.go @@ -0,0 +1,3 @@ +package api + +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml diff --git a/examples/overlay/api/impl.go b/examples/overlay/api/impl.go new file mode 100644 index 0000000000..4224ef2fe7 --- /dev/null +++ b/examples/overlay/api/impl.go @@ -0,0 +1,25 @@ +package api + +import ( + "encoding/json" + "net/http" +) + +// ensure that we've conformed to the `ServerInterface` with a compile-time check +var _ ServerInterface = (*Server)(nil) + +type Server struct{} + +func NewServer() Server { + return Server{} +} + +// (GET /ping) +func (Server) GetPing(w http.ResponseWriter, r *http.Request) { + resp := OverriddenPong{ + Ping: "pong", + } + + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(resp) +} diff --git a/examples/overlay/api/overlay.yaml b/examples/overlay/api/overlay.yaml new file mode 100644 index 0000000000..b2be4c5bae --- /dev/null +++ b/examples/overlay/api/overlay.yaml @@ -0,0 +1,53 @@ +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: $.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: "$" + update: + info: + x-overlay-applied: structured-overlay + +- 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..0128a32e97 --- /dev/null +++ b/examples/overlay/api/ping.gen.go @@ -0,0 +1,256 @@ +// 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/gzip" + "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("GET") + + return r +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/1xSwW4UMQz9lchwAGl2s+2KS24VQmjFYVeCW9VDmvHuuMzEIfGUVlX+HTmzS6EnJ86L", + "33u2XyDwlDhilALuBUoYcPLteOB40pgyJ8xC2LKJliw++SmNCA6S4jqQ56S3IlkRtXaQ8ddMGXtwt8u3", + "u78ovn/AINDB0+rEq+gnTe4fMWfqe4yNumoNikdWOiFpZF8WWiNsKPYUvKAZ+Lfe54JGBjT7hPHmsDNa", + "bvTPpiQMdFQocTQfBpFUnLUnkmG+Xwee7P5mZ8/o1fd/0R+hg0fMhTiCg6v1Zr1pmvkM9imNpAbV9hxk", + "zthfHqF2wAmjTwQOtue/ycvQ+mh9P1G0fhYuwY9LV2sH9tLgE4qGHkvIlGSR8HnA8NPI4KVZVZtUTJ5j", + "pHgy+2/QOHMTv1NdX1EO1OaTsSSOZZni9WajIXAUjI2nWVlc24eiZJdl0NP7jEdw8M6+bos9r4p9Hdb/", + "WhOKuZC2fSiYtZngbt/a+jGg6fHo51HMglpDB3MewYHOy1k7cvDjwEXc9tPV9RbqXa21/gkAAP//2FDh", + "Ob8CAAA=", +} + +// 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/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()) +} From aa2316bb698306241571f67c6d7fe0fd2c700fba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:33:42 +0000 Subject: [PATCH 007/293] chore(deps): update module github.com/golangci/golangci-lint to v1.60.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 55ace4eba2..e2a8c35752 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.60.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.60.2 .PHONY: tools tools: $(GOBIN)/golangci-lint From d232e9efa9f54ee20ca60df885595bd23dc86759 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 02:38:24 +0000 Subject: [PATCH 008/293] chore(deps): update module github.com/golangci/golangci-lint to v1.60.3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e2a8c35752..5eacf618da 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.60.2 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.60.3 .PHONY: tools tools: $(GOBIN)/golangci-lint From 0cc58ab516cfde9c4936a6dfa34456259b8368e3 Mon Sep 17 00:00:00 2001 From: Egor Rudkov Date: Sun, 8 Sep 2024 18:37:06 +0200 Subject: [PATCH 009/293] docs: reference new org's JSON Schema URL (#1748) The schema validation URL in the YAML config example leads to the old org name. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07857cbcb3..d4111aaf12 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ 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/HEAD/configuration-schema.json package: api # ... ``` From d07bc9f97bb1b10fe5a373c864bca9c3b9af371c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 8 Sep 2024 18:46:42 +0100 Subject: [PATCH 010/293] docs(overlay): improve Overlay docs As it's more helpful to show off Structured Overlays as our recommended option. This also corrects the Structural Overlay in the example. --- README.md | 13 +++++++++++++ examples/overlay/api/overlay.yaml | 22 +++++++++++++++++----- examples/overlay/api/ping.gen.go | 16 ++++++++-------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d4111aaf12..37b019560f 100644 --- a/README.md +++ b/README.md @@ -2005,6 +2005,17 @@ 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 @@ -2030,6 +2041,8 @@ output-options: This then completely removes the DELETE endpoint _before_ we even start to parse the specification in `oapi-codegen`, so it's as if your specification was provided without that endpoint. +Additionally, we can override other pieces of metadata, such as the description for operations. + Check out [the overlay example](examples/overlay/) for the full code, and some more complex examples. ## Generating Nullable types diff --git a/examples/overlay/api/overlay.yaml b/examples/overlay/api/overlay.yaml index b2be4c5bae..8ee1d72fd5 100644 --- a/examples/overlay/api/overlay.yaml +++ b/examples/overlay/api/overlay.yaml @@ -3,6 +3,23 @@ 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: @@ -14,11 +31,6 @@ actions: update: x-go-name: OverriddenPong -- target: "$" - update: - info: - x-overlay-applied: structured-overlay - - target: $.paths['/ping'].get description: Override the poorly documented internal description for the ping API update: diff --git a/examples/overlay/api/ping.gen.go b/examples/overlay/api/ping.gen.go index 0128a32e97..d36bdd55b3 100644 --- a/examples/overlay/api/ping.gen.go +++ b/examples/overlay/api/ping.gen.go @@ -173,14 +173,14 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/1xSwW4UMQz9lchwAGl2s+2KS24VQmjFYVeCW9VDmvHuuMzEIfGUVlX+HTmzS6EnJ86L", - "33u2XyDwlDhilALuBUoYcPLteOB40pgyJ8xC2LKJliw++SmNCA6S4jqQ56S3IlkRtXaQ8ddMGXtwt8u3", - "u78ovn/AINDB0+rEq+gnTe4fMWfqe4yNumoNikdWOiFpZF8WWiNsKPYUvKAZ+Lfe54JGBjT7hPHmsDNa", - "bvTPpiQMdFQocTQfBpFUnLUnkmG+Xwee7P5mZ8/o1fd/0R+hg0fMhTiCg6v1Zr1pmvkM9imNpAbV9hxk", - "zthfHqF2wAmjTwQOtue/ycvQ+mh9P1G0fhYuwY9LV2sH9tLgE4qGHkvIlGSR8HnA8NPI4KVZVZtUTJ5j", - "pHgy+2/QOHMTv1NdX1EO1OaTsSSOZZni9WajIXAUjI2nWVlc24eiZJdl0NP7jEdw8M6+bos9r4p9Hdb/", - "WhOKuZC2fSiYtZngbt/a+jGg6fHo51HMglpDB3MewYHOy1k7cvDjwEXc9tPV9RbqXa21/gkAAP//2FDh", - "Ob8CAAA=", + "H4sIAAAAAAAC/1xSwW7UMBD9FWvgAFJ2ve2Ki28VQmjFYVeCW9WD60xil8Rj7ElpVfnf0Ti7FHqaePLs", + "997MewFHc6KIkQuYFyjO42zb54niKDVlSpg5YOumsHbxyc5pQjCQBNcBPyc5Fc6CqLWDjL+WkLEHc7te", + "u/uLovsHdAwdPG1G2kQ7S/P4iDmHvsfYqKu8EeJAQseBG9mXlVYxqRD74Cyj8vRbzktBxR7VMWG8OR2U", + "PDfZZ1USujAINFBUHzxzKkbrMbBf7reOZn28OegzevP9X/RH6OARcwkUwcDVdrfdNc10BtuUpiAGxfbi", + "eMnYX35C7YASRpsCGNif7ybLvs1R234OUduFqTg7rVOtHejLgEdkKT0Wl0PiVcJnj+6nYm+5WRWboai8", + "xBjiqI7foHHmJv4gur4in0LbT8aSKJZ1i9e7nRRHkTE2nmZlda0fipBdwiBf7zMOYOCdfk2LPkdFvy7r", + "f60nzAPlWVkllpSkAQu3ZBTMMlYwt28N/vCoehzsMrFaUVvoYMkTGJDNGa0ncnbyVNjsP11d76He1Vrr", + "nwAAAP//QsRK0MkCAAA=", } // GetSwagger returns the content of the embedded swagger specification file From 2be24b11ae0f0a6610cffc0f1c1b43ea83fd82aa Mon Sep 17 00:00:00 2001 From: Joseph Riddle Date: Sun, 8 Sep 2024 13:00:14 -0700 Subject: [PATCH 011/293] docs: correct sentence in `CONTRIBUTING.md` (#1750) Change "likely" to "unlikely" where the context indicates the latter was meant. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 137f45c25f..56182260fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. From 0502e95d86bb6c4194eaa51f1ff0d0d1b3439931 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 15 Sep 2024 20:50:13 +0100 Subject: [PATCH 012/293] docs: add link to OpenSSF Best Practices badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 37b019560f..082c7d97d5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # `oapi-codegen` +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9450/badge)](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. From 19f64b2da4fab3ffdfc943b83fbaecb44609c32d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 11:01:32 +0100 Subject: [PATCH 013/293] docs(sponsors): add Cybozu Via OpenCollective. --- .github/sponsors/cybozu.svg | 19 +++++++++++++++++++ README.md | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100644 .github/sponsors/cybozu.svg diff --git a/.github/sponsors/cybozu.svg b/.github/sponsors/cybozu.svg new file mode 100644 index 0000000000..6691fbd916 --- /dev/null +++ b/.github/sponsors/cybozu.svg @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/README.md b/README.md index 082c7d97d5..3cd2e4fa5c 100644 --- a/README.md +++ b/README.md @@ -4101,4 +4101,10 @@ We are currently generously sponsored by the following folks, each of whom provi

+

+ + Cybozu logo + +

+ (Note that the order of appearance the order in which sponsorship was received) From bb8696c68157de424bee23978bb595540b0842fc Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 20 Sep 2024 03:07:50 -0700 Subject: [PATCH 014/293] feat: handle `<` and `>` in property or type names (#1740) --- pkg/codegen/utils.go | 4 ++++ pkg/codegen/utils_test.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 1e1e76f762..c9d50d2544 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -776,6 +776,10 @@ func typeNamePrefix(name string) (prefix string) { prefix += "Tilde" case '=': prefix += "Equal" + case '>': + prefix += "GreaterThan" + case '<': + prefix += "LessThan" case '#': prefix += "Hash" case '.': diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index a55e648e8a..7123f8f080 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -594,6 +594,10 @@ func TestSchemaNameToTypeName(t *testing.T) { "=3": "Equal3", "#Tag": "HashTag", ".com": "DotCom", + ">=": "GreaterThanEqual", + "<=": "LessThanEqual", + "<": "LessThan", + ">": "GreaterThan", } { assert.Equal(t, want, SchemaNameToTypeName(in)) } From 4471ef519022ac17131bf47bd84f9074052c5825 Mon Sep 17 00:00:00 2001 From: Alysson Ribeiro <15274059+sonalys@users.noreply.github.com> Date: Fri, 20 Sep 2024 07:12:04 -0300 Subject: [PATCH 015/293] feat(std-http): accept Mux as interface instead of *http.ServeMux (#1720) As noted in #1718, by accepting an interface instead of an implementation, we can make this a little bit more extensible and usable for `Mux`-like things. Closes #1718 --- README.md | 2 +- examples/authenticated-api/stdhttp/api/api.gen.go | 12 +++++++++--- examples/minimal-server/stdhttp/api/ping.gen.go | 12 +++++++++--- .../petstore-expanded/stdhttp/api/petstore.gen.go | 12 +++++++++--- internal/test/strict-server/stdhttp/server.gen.go | 12 +++++++++--- pkg/codegen/templates/stdhttp/std-http-handler.tmpl | 12 +++++++++--- 6 files changed, 46 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3cd2e4fa5c..a5ab62bcdd 100644 --- a/README.md +++ b/README.md @@ -652,7 +652,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, }) diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index a631cdd8c4..91ced48c3d 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -540,21 +540,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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + 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, diff --git a/examples/minimal-server/stdhttp/api/ping.gen.go b/examples/minimal-server/stdhttp/api/ping.gen.go index 3ce4c5e3e1..794f8d817f 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + 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, diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index 733981ff92..3f99776250 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -259,21 +259,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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + 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, diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 6a3b2537a9..28c36a7ac7 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -376,21 +376,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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + 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, diff --git a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl index 9542fabae1..bed4685c74 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + 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, From 2c1ca0e8d2e84aafd852f0afd3e45b0216cc6065 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:14:57 +0000 Subject: [PATCH 016/293] fix(deps): update module golang.org/x/text to v0.18.0 --- examples/authenticated-api/stdhttp/go.mod | 4 ++-- examples/authenticated-api/stdhttp/go.sum | 12 ++++++------ examples/go.mod | 4 ++-- examples/go.sum | 12 ++++++------ examples/minimal-server/stdhttp/go.mod | 4 ++-- examples/minimal-server/stdhttp/go.sum | 12 ++++++------ examples/petstore-expanded/stdhttp/go.mod | 4 ++-- examples/petstore-expanded/stdhttp/go.sum | 12 ++++++------ go.mod | 4 ++-- go.sum | 12 ++++++------ internal/test/go.mod | 4 ++-- internal/test/go.sum | 12 ++++++------ internal/test/strict-server/stdhttp/go.mod | 4 ++-- internal/test/strict-server/stdhttp/go.sum | 12 ++++++------ 14 files changed, 56 insertions(+), 56 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 4a92656040..2df22d9bdc 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -37,8 +37,8 @@ require ( github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index b0ae29103e..06ae5d4617 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -154,8 +154,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -191,15 +191,15 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/examples/go.mod b/examples/go.mod index c1df048441..2066e1225f 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -109,9 +109,9 @@ require ( 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/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 diff --git a/examples/go.sum b/examples/go.sum index 5fd02f0c22..786e67c039 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -349,8 +349,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -385,8 +385,8 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -396,8 +396,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 829ac139b3..41cde25da6 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -19,8 +19,8 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 2e22e64369..271a54f584 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -106,8 +106,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -130,13 +130,13 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 14d2bc2594..b49ad323c4 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -30,8 +30,8 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 1ae6d4cb35..1d7deb2f40 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -123,8 +123,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -147,13 +147,13 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/go.mod b/go.mod index 89d52354d8..7b15915468 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/getkin/kin-openapi v0.127.0 github.com/speakeasy-api/openapi-overlay v0.9.0 github.com/stretchr/testify v1.9.0 - golang.org/x/text v0.15.0 - golang.org/x/tools v0.21.0 + golang.org/x/text v0.18.0 + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 2e22e64369..271a54f584 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -130,13 +130,13 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 6cd91ad290..a3e01f4ec9 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -97,9 +97,9 @@ require ( 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/text v0.18.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index c020fc1083..05f5fecaa5 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -316,8 +316,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -348,16 +348,16 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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/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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 6887d5baa5..24161ac4e0 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -31,8 +31,8 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // 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 + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 711491dfe6..1c76fe6548 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -119,8 +119,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -143,13 +143,13 @@ 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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= From 1b20051644e71e229c33809e5acccc69f155a64c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 11:38:19 +0100 Subject: [PATCH 017/293] build: check results of matrix jobs This makes sure that we can add these as required status checks, which we can't easily do with a matrix job due to the differing names for each version used. Via [0]. [0]: https://github.com/orgs/community/discussions/26822#discussioncomment-3305794 --- .github/workflows/ci.yml | 14 ++++++++++++++ .github/workflows/generate.yml | 14 ++++++++++++++ .github/workflows/lint.yml | 14 ++++++++++++++ .github/workflows/tidy.yml | 14 ++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76ce74f913..f1d7d02d55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,3 +29,17 @@ jobs: - name: Build run: go build ./cmd/oapi-codegen + + results: + if: ${{ always() }} + runs-on: ubuntu-latest + name: Check results + needs: [build] + steps: + - run: | + result="${{ needs.build.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 912040ed14..588f63411e 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -29,3 +29,17 @@ jobs: - name: Check for no untracked files run: git status && git diff-index --exit-code -p HEAD -- + + results: + if: ${{ always() }} + runs-on: ubuntu-latest + name: Check results + needs: [build] + steps: + - run: | + result="${{ needs.build.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4b27e4c7c5..07cdf5d6c8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,3 +26,17 @@ jobs: 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 + + results: + if: ${{ always() }} + runs-on: ubuntu-latest + name: Check results + needs: [build] + steps: + - run: | + result="${{ needs.build.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 3fa0173d2a..cd96670676 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -29,3 +29,17 @@ jobs: 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 + + results: + if: ${{ always() }} + runs-on: ubuntu-latest + name: Check results + needs: [build] + steps: + - run: | + result="${{ needs.build.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi From b22278db7f4b5488135d7f74a1e8391291505b80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:45:31 +0000 Subject: [PATCH 018/293] chore(deps): update module github.com/golangci/golangci-lint to v1.61.0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5eacf618da..73e1cd3ac1 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.60.3 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.61.0 .PHONY: tools tools: $(GOBIN)/golangci-lint From 3d6764e2f0f056f0d6ec48eb6f030b9586ac5bc3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 12:12:07 +0100 Subject: [PATCH 019/293] docs(tests): add an example of using `in: cookie` Ahead of being able to fix #924, we should have an example that shows the before-and-after usage of what this looks like. --- internal/test/cookies/config.yaml | 6 + internal/test/cookies/cookies.gen.go | 195 +++++++++++++++++++++++++++ internal/test/cookies/generate.go | 3 + internal/test/cookies/spec.yaml | 18 +++ 4 files changed, 222 insertions(+) create mode 100644 internal/test/cookies/config.yaml create mode 100644 internal/test/cookies/cookies.gen.go create mode 100644 internal/test/cookies/generate.go create mode 100644 internal/test/cookies/spec.yaml diff --git a/internal/test/cookies/config.yaml b/internal/test/cookies/config.yaml new file mode 100644 index 0000000000..2d1cbd4300 --- /dev/null +++ b/internal/test/cookies/config.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=../../../configuration-schema.json +package: cookies +generate: + chi-server: true + models: true +output: cookies.gen.go diff --git a/internal/test/cookies/cookies.gen.go b/internal/test/cookies/cookies.gen.go new file mode 100644 index 0000000000..4f6914833f --- /dev/null +++ b/internal/test/cookies/cookies.gen.go @@ -0,0 +1,195 @@ +// 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"` +} + +// 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 + + // 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{Explode: true, Required: false}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "authId", Err: err}) + return + } + params.AuthId = &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..62edbe3d66 --- /dev/null +++ b/internal/test/cookies/spec.yaml @@ -0,0 +1,18 @@ +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 + responses: + 204: + description: no content From 58a5d2d454590120673d065139af0bdd028edb6a Mon Sep 17 00:00:00 2001 From: andremarianiello Date: Fri, 20 Sep 2024 07:25:24 -0400 Subject: [PATCH 020/293] fix(cookies): wrap `cookie` variables in block scope (#1687) As noted in #924, the existing behaviour leads to a compliation error when multiple cookie parameters are set. To correctly manage this, we can create a separate block scoped `cookie` variable. Closes #924. Co-authored-by: Jamie Tanna --- internal/test/cookies/cookies.gen.go | 36 ++++++++++++++----- internal/test/cookies/spec.yaml | 6 ++++ pkg/codegen/templates/chi/chi-middleware.tmpl | 2 ++ .../templates/gorilla/gorilla-middleware.tmpl | 2 ++ .../stdhttp/std-http-middleware.tmpl | 2 ++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/internal/test/cookies/cookies.gen.go b/internal/test/cookies/cookies.gen.go index 4f6914833f..5168bbd153 100644 --- a/internal/test/cookies/cookies.gen.go +++ b/internal/test/cookies/cookies.gen.go @@ -15,6 +15,9 @@ import ( 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. @@ -50,17 +53,34 @@ func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.R // Parameter object where we will unmarshal all parameters from the context var params CookieParamsParams - var cookie *http.Cookie + { + 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{Explode: true, Required: false}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "authId", Err: err}) + return + } + params.AuthId = &value - if cookie, err = r.Cookie("authId"); err == nil { - var value string - err = runtime.BindStyledParameterWithOptions("simple", "authId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false}) - 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{Explode: true, Required: false}) + 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) { diff --git a/internal/test/cookies/spec.yaml b/internal/test/cookies/spec.yaml index 62edbe3d66..f30596224f 100644 --- a/internal/test/cookies/spec.yaml +++ b/internal/test/cookies/spec.yaml @@ -13,6 +13,12 @@ paths: 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/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index ced82b4c42..9423a67f2c 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -129,6 +129,7 @@ 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 { @@ -173,6 +174,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } {{- end}} + } {{end}} {{end}} diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index 4353c9f42f..85b04c89fa 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -129,6 +129,7 @@ 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 { @@ -173,6 +174,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } {{- 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..19f1fe2950 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -129,6 +129,7 @@ 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 { @@ -173,6 +174,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } {{- end}} + } {{end}} {{end}} From 58c78948ca8a8847c8eb26bab9522905d4f5c662 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 14:55:21 +0100 Subject: [PATCH 021/293] docs: remove `deepmap/oapi-codegen` references To make it easier to find i.e. references to change in pending PRs, from before the org move. --- CONTRIBUTING.md | 2 +- README.md | 54 +++++++++---------- cmd/oapi-codegen/oapi-codegen.go | 2 +- configuration-schema.json | 12 ++--- examples/anyof-allof-oneof/api.yaml | 2 +- examples/custom-client-type/doc.go | 2 +- examples/only-models/api.yaml | 2 +- internal/test/issues/issue-1093/doc.go | 2 +- pkg/codegen/codegen_test.go | 2 +- pkg/codegen/configuration.go | 12 ++--- pkg/codegen/merge_schemas.go | 2 +- pkg/codegen/schema.go | 2 +- pkg/codegen/template_helpers.go | 2 +- .../test_specs/remote-external-reference.yaml | 2 +- 14 files changed, 50 insertions(+), 50 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56182260fa..3674b1cf16 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 diff --git a/README.md b/README.md index a5ab62bcdd..434592b4e1 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Which then means you can invoke it like so: ### 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. @@ -91,7 +91,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 ``` @@ -372,7 +372,7 @@ 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) - 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)) @@ -1502,7 +1502,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! @@ -1577,7 +1577,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: @@ -1744,7 +1744,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: @@ -1777,7 +1777,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: @@ -1806,7 +1806,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: @@ -1895,7 +1895,7 @@ components: And finally we have our 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 # admin/cfg.yaml package: admin output: server.gen.go @@ -1917,7 +1917,7 @@ error generating code: error creating operation definitions: error generating re This is because `oapi-codegen` requires: ```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: @@ -2029,7 +2029,7 @@ actions: And our configuration file for `oapi-codegen`: ```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 output: ping.gen.go generate: @@ -2077,7 +2077,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: @@ -3021,7 +3021,7 @@ Middleware library > [!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 @@ -3037,7 +3037,7 @@ If you're using a specification with [Security Schemes](https://spec.openapis.or > > To perform authentication, you will need to use the [validation middleware](#request-response-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). @@ -3091,7 +3091,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: @@ -3112,23 +3112,23 @@ 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) +> 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] @@ -3139,7 +3139,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: @@ -3157,7 +3157,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`) @@ -3166,7 +3166,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. @@ -3789,7 +3789,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 @@ -4024,7 +4024,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: [] @@ -4061,9 +4061,9 @@ We'll be aware of the issue, and will work to update both the core `oapi-codegen ## 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/deepmap/oapi-codegen/discussions/1606), we're looking to make this a more sustainable project in the future. +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. -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 💜 +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 💜 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. diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 1d166f8ba6..2d05cff92c 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -297,7 +297,7 @@ func main() { } 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.Println("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 { diff --git a/configuration-schema.json b/configuration-schema.json index 6344cba2b8..e4bbfe1bc3 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -66,15 +66,15 @@ "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-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 +82,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 +90,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", 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/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/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/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/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 1d752601b3..7b22faed01 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` ) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index d60eb5ed8b..c2d36f9df0 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -140,26 +140,26 @@ 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"` // 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 +167,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 diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index d2ab35bb7d..04e7b2fa2b 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -238,7 +238,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/schema.go b/pkg/codegen/schema.go index 3d4bdbbddb..86b82a439c 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -513,7 +513,7 @@ 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 { typeName, err = extString(extension) diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 62ea244c8b..b9efe2cf45 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -225,7 +225,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) { 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 From dad645e4bf8c2baf530b354d192d03c52f59c1f9 Mon Sep 17 00:00:00 2001 From: Daleef Rahman Date: Fri, 20 Sep 2024 18:26:30 +0400 Subject: [PATCH 022/293] fix: correctly generate structs and properties for `anyOf`s (#1178) fix: correctly generate structs and properties for `anyOf`s As noted in #1121, we have cases where an `anyOf` can end up producing a type such as: type GetPetsResponse struct { Body []byte HTTPResponse *http.Response JSON200 *struct { Data *[]200_Data_Item`json:"data,omitempty"` } } This does not end up compiling, as Go doesn't allow identifiers to start with a number. Therefore, we need to make sure that `PathToTypeName` includes the `operationId` to generate a non-numeric name. Additionally, even if that did compile, we also don't end up generating the type that is referenced, so we need to make sure that we generate any `AdditionalTypeDefinitions` present. Closes #1121. Co-authored-by: Daleef Rahman Kalai Co-authored-by: Daleef Rahman Kalai Co-authored-by: Jamie Tanna --- .../test/any_of/codegen/inline/config.yaml | 6 + .../test/any_of/codegen/inline/generate.go | 3 + .../test/any_of/codegen/inline/openapi.gen.go | 328 ++++++++++++++ internal/test/any_of/codegen/inline/spec.yaml | 81 ++++ .../any_of/codegen/ref_schema/config.yaml | 6 + .../any_of/codegen/ref_schema/generate.go | 3 + .../any_of/codegen/ref_schema/openapi.gen.go | 420 ++++++++++++++++++ .../test/any_of/codegen/ref_schema/spec.yaml | 81 ++++ .../test/strict-server/client/client.gen.go | 1 + pkg/codegen/operations.go | 7 +- pkg/codegen/schema.go | 2 + .../templates/client-with-responses.tmpl | 9 +- 12 files changed, 943 insertions(+), 4 deletions(-) create mode 100644 internal/test/any_of/codegen/inline/config.yaml create mode 100644 internal/test/any_of/codegen/inline/generate.go create mode 100644 internal/test/any_of/codegen/inline/openapi.gen.go create mode 100644 internal/test/any_of/codegen/inline/spec.yaml create mode 100644 internal/test/any_of/codegen/ref_schema/config.yaml create mode 100644 internal/test/any_of/codegen/ref_schema/generate.go create mode 100644 internal/test/any_of/codegen/ref_schema/openapi.gen.go create mode 100644 internal/test/any_of/codegen/ref_schema/spec.yaml 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..d3f34bec6e --- /dev/null +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -0,0 +1,328 @@ +// 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" +) + +const ( + ApiKeyAuthScopes = "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"` +} + +// 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("GET", 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 *[]GetPets_200_Data_Item `json:"data,omitempty"` + } +} +type GetPets_200_Data_Item struct { + union json.RawMessage +} + +// 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 +} + +// 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 *[]GetPets_200_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(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 +} + +// 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+"/pets", wrapper.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..38f87c47be --- /dev/null +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -0,0 +1,420 @@ +// 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 = "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"` +} + +// 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("GET", 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 +} + +// 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 +} + +// 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(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 +} + +// 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+"/pets", wrapper.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/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index e7959520e4..5bf1dffb3f 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -1261,6 +1261,7 @@ type UnionExampleResponse struct { union json.RawMessage } } +type UnionExample2000 = string // Status returns HTTPResponse.Status func (r UnionExampleResponse) Status() string { diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index da903810db..3b0f130162 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -297,7 +297,7 @@ 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}) + responseSchema, err := GenerateGoSchema(contentType.Schema, []string{o.OperationId, responseName}) if err != nil { return nil, fmt.Errorf("Unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) } @@ -331,8 +331,9 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini TypeName: typeName, Schema: responseSchema, }, - ResponseName: responseName, - ContentTypeName: contentTypeName, + ResponseName: responseName, + ContentTypeName: contentTypeName, + AdditionalTypeDefinitions: responseSchema.GetAdditionalTypeDefs(), } if IsGoTypeReference(responseRef.Ref) { refType, err := RefPathToGoType(responseRef.Ref) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 86b82a439c..2cef0023fe 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -199,6 +199,8 @@ type ResponseTypeDefinition struct { // The type name of a response model. ResponseName string + + AdditionalTypeDefinitions []TypeDefinition } func (t *TypeDefinition) IsAlias() bool { diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index c0b3ca5688..908f21476a 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -44,14 +44,21 @@ 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}} } +{{- range $responseTypeDefinitions}} + {{- range .AdditionalTypeDefinitions}} + type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}} + {{- end}} +{{- end}} + // Status returns HTTPResponse.Status func (r {{genResponseTypeName $opid | ucFirst}}) Status() string { if r.HTTPResponse != nil { From 3a8fc20a08cd6dbfe9c9ecaadb50eb41e8f1f75e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 16:34:21 +0100 Subject: [PATCH 023/293] chore(tests): add test case for #1676 Adds a test cases for #1676. --- internal/test/issues/issue-1676/api.yaml | 17 ++ internal/test/issues/issue-1676/cfg.yaml | 7 + internal/test/issues/issue-1676/generate.go | 3 + internal/test/issues/issue-1676/ping.gen.go | 243 ++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 internal/test/issues/issue-1676/api.yaml create mode 100644 internal/test/issues/issue-1676/cfg.yaml create mode 100644 internal/test/issues/issue-1676/generate.go create mode 100644 internal/test/issues/issue-1676/ping.gen.go 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..8f2e895b69 --- /dev/null +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -0,0 +1,243 @@ +// 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" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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("GET") + + return r +} + +type GetPingRequestObject struct { +} + +type GetPingResponseObject interface { + VisitGetPingResponse(w http.ResponseWriter) error +} + +type GetPing200ResponseHeaders struct { + MyHeader string +} + +type GetPing200TextResponse string + +func (response GetPing200TextResponse) VisitGetPingResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") + 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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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)) + } +} From 891a067256b2cec51d70d06adbd7d04b619138e3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 16:39:38 +0100 Subject: [PATCH 024/293] Revert "fix(template): fix strict-interface template to make sure text response content type uses string type (#1132)" This reverts commit df2cf430268058a881a99609ba80236f9ca0dd20. As raised in #1676, this was a breaking change, and means that `text/plain` responses cannot interact with their headers. Closes #1676. --- internal/test/issues/issue-1676/ping.gen.go | 5 ++++- pkg/codegen/templates/strict/strict-interface.tmpl | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go index 8f2e895b69..dcfddc3bc6 100644 --- a/internal/test/issues/issue-1676/ping.gen.go +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -171,7 +171,10 @@ type GetPing200ResponseHeaders struct { MyHeader string } -type GetPing200TextResponse string +type GetPing200TextResponse struct { + Body string + Headers GetPing200ResponseHeaders +} func (response GetPing200TextResponse) VisitGetPingResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "text/plain") diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index b26edd4678..e19936d6a7 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -39,9 +39,7 @@ {{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 $fixedStatusCode $isRef -}} {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (eq .NameTag "Multipart") -}} type {{$receiverTypeName}} {{$ref}}{{.NameTagOrContentType}}Response {{else if $isExternalRef -}} From 3aa1efbd370b860539884f5f992bf2ee540fa368 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 21:06:57 +0100 Subject: [PATCH 025/293] feat: allow `import-mapping` to the current package (#1774) To simplify working with large OpenAPI specs, a good option is to split this into multiple files. However, a long-standing issue with `oapi-codegen`, as noted in #400, is that when using multiple files for your OpenAPI specifications, the Import Mapping functionality requires splitting each file into a separate package. To improve this experience, we can allow using a new "magic" package name, `-`, and omit the need to perform package imports. This also updates our existing `import-mapping` example, and adds a new example for this functionality, as well as clarifying this in the docs. We simplify the existing `import-mapping` example, as the duplicated `User` type causes compilation issues. To actually implement this, we need to tweak our `refPathToGoType` logic. Closes #400. Co-authored-by: Dj Gilcrease --- README.md | 93 +++++- configuration-schema.json | 2 +- examples/import-mapping/admin/api.yaml | 6 +- .../{ => multiplepackages}/admin/cfg.yaml | 2 +- .../{ => multiplepackages}/admin/generate.go | 2 +- .../admin/server.gen.go | 4 - .../{ => multiplepackages}/common/cfg.yaml | 0 .../{ => multiplepackages}/common/generate.go | 2 +- .../common/types.gen.go | 0 .../import-mapping/samepackage/cfg-api.yaml | 12 + .../import-mapping/samepackage/cfg-user.yaml | 8 + .../import-mapping/samepackage/generate.go | 4 + .../import-mapping/samepackage/server.gen.go | 266 ++++++++++++++++++ .../import-mapping/samepackage/user.gen.go | 9 + pkg/codegen/codegen.go | 10 +- pkg/codegen/templates/inline.tmpl | 4 +- pkg/codegen/utils.go | 73 +++-- pkg/codegen/utils_test.go | 17 +- 18 files changed, 452 insertions(+), 62 deletions(-) rename examples/import-mapping/{ => multiplepackages}/admin/cfg.yaml (87%) rename examples/import-mapping/{ => multiplepackages}/admin/generate.go (60%) rename examples/import-mapping/{ => multiplepackages}/admin/server.gen.go (97%) rename examples/import-mapping/{ => multiplepackages}/common/cfg.yaml (100%) rename examples/import-mapping/{ => multiplepackages}/common/generate.go (60%) rename examples/import-mapping/{ => multiplepackages}/common/types.gen.go (100%) create mode 100644 examples/import-mapping/samepackage/cfg-api.yaml create mode 100644 examples/import-mapping/samepackage/cfg-user.yaml create mode 100644 examples/import-mapping/samepackage/generate.go create mode 100644 examples/import-mapping/samepackage/server.gen.go create mode 100644 examples/import-mapping/samepackage/user.gen.go diff --git a/README.md b/README.md index 434592b4e1..7bff27b3c4 100644 --- a/README.md +++ b/README.md @@ -1824,10 +1824,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". @@ -1869,11 +1872,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: @@ -1892,7 +1891,75 @@ 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 spec for a given package + + + +> [!TIP] +> Since `oapi-codegen` v2.4.0, it is now possible to split large OpenAPI specifications into the same Go package, using the "self" mapping (denoted by a `-`) when using Import Mapping. +> +> This is an improvement on the previous model, which would require splitting files across multiple packages. + +> [!NOTE] +> You still need to have multiple `go generate`s, and any other configuration files. + +To get `oapi-codegen`'s single-package support working, we need multiple calls to `oapi-codegen`, one call per OpenAPI spec file: + +```sh +$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-api.yaml ../admin/api.yaml +$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-user.yaml ../common/api.yaml +``` + +This therefore means that we need multiple configuration files, such as `cfg-api.yaml`: + +```yaml +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json +package: samepackage +output: server.gen.go +generate: + models: true + chi-server: true + strict-server: true +output-options: + # to make sure that all types are generated + skip-prune: true +import-mapping: + user.yaml: "-" +``` + +And then our `cfg-user.yaml`: + +```yaml +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json +package: samepackage +output: user.gen.go +generate: + models: true +output-options: + # to make sure that all types are generated + skip-prune: true +``` + +From here, `oapi-codegen` will generate multiple Go files, all within the same package, which can be used to break down your large OpenAPI specifications, and generate only the subsets of code needed for each part of the spec. + +Check out [the import-mapping/samepackage example](examples/import-mapping/samepackage) for the full code. + +### Using multiple packages, with one OpenAPI spec per package + +To get `oapi-codegen`'s multi-package support working, we need to set up our directory structure: + +``` +├── admin +│   ├── cfg.yaml +│   └── generate.go +└── common + ├── cfg.yaml +    └── generate.go +``` + +We could start with our configuration file for our admin API spec: ```yaml # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json @@ -1914,7 +1981,7 @@ 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/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json @@ -1945,9 +2012,9 @@ 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 example](examples/import-mapping/) for the full code. +Check out [the import-mapping/multiplepackages example](examples/import-mapping/multiplepackages/) for the full code. ## Modifying the input OpenAPI Specification diff --git a/configuration-schema.json b/configuration-schema.json index e4bbfe1bc3..745c07406c 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -221,7 +221,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": { 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/admin/generate.go b/examples/import-mapping/multiplepackages/admin/generate.go similarity index 60% rename from examples/import-mapping/admin/generate.go rename to examples/import-mapping/multiplepackages/admin/generate.go index 0cc4cece11..304d122d22 100644 --- a/examples/import-mapping/admin/generate.go +++ b/examples/import-mapping/multiplepackages/admin/generate.go @@ -1,3 +1,3 @@ package admin -//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../admin/api.yaml diff --git a/examples/import-mapping/admin/server.gen.go b/examples/import-mapping/multiplepackages/admin/server.gen.go similarity index 97% rename from examples/import-mapping/admin/server.gen.go rename to examples/import-mapping/multiplepackages/admin/server.gen.go index 84f881f102..36e33e4c4c 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 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/common/generate.go b/examples/import-mapping/multiplepackages/common/generate.go similarity index 60% rename from examples/import-mapping/common/generate.go rename to examples/import-mapping/multiplepackages/common/generate.go index 4e7fe60ec4..2e515e9342 100644 --- a/examples/import-mapping/common/generate.go +++ b/examples/import-mapping/multiplepackages/common/generate.go @@ -1,3 +1,3 @@ package common -//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../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..bd9445262b --- /dev/null +++ b/examples/import-mapping/samepackage/server.gen.go @@ -0,0 +1,266 @@ +// 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 ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/oapi-codegen/runtime" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" + 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 + + // ------------- 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}) + 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +// 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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 7163998d19..632f649e23 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -66,10 +66,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 @@ -89,7 +97,7 @@ func constructImportMapping(importMapping map[string]string) importMap { sort.Strings(packagePaths) for _, packagePath := range packagePaths { - if _, ok := pathToName[packagePath]; !ok { + if _, ok := pathToName[packagePath]; !ok && packagePath != importMappingCurrentPackage { pathToName[packagePath] = fmt.Sprintf("externalRef%d", len(pathToName)) } } diff --git a/pkg/codegen/templates/inline.tmpl b/pkg/codegen/templates/inline.tmpl index 0124121566..851ea59b26 100644 --- a/pkg/codegen/templates/inline.tmpl +++ b/pkg/codegen/templates/inline.tmpl @@ -43,14 +43,14 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { {{ if .ImportMapping }} pathPrefix := path.Dir(pathToFile) {{ end }} - {{ range $key, $value := .ImportMapping }} + {{ range $key, $value := .ImportMapping }}{{- if ne $value.Path "-"}} for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(pathPrefix, "{{ $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 } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index c9d50d2544..e82d5e3e3c 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -441,44 +441,59 @@ func RefPathToGoType(refPath string) (string, error) { // refPathToGoType returns the Go typename for refPath given its func refPathToGoType(refPath string, local bool) (string, error) { if refPath[0] == '#' { - pathParts := strings.Split(refPath, "/") - depth := len(pathParts) - if local { - if depth != 4 { - return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) - } - } else if depth != 4 && depth != 2 { - return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) - } - - // Schemas may have been renamed locally, so look up the actual name in - // the spec. - name, err := findSchemaNameByRefPath(refPath, globalState.spec) - if err != nil { - return "", fmt.Errorf("error finding ref: %s in spec: %v", refPath, err) - } - if name != "" { - return name, nil - } - // lastPart now stores the final element of the type path. This is what - // we use as the base for a type name. - lastPart := pathParts[len(pathParts)-1] - return SchemaNameToTypeName(lastPart), nil + return refPathToGoTypeSelf(refPath, local) } pathParts := strings.Split(refPath, "#") if len(pathParts) != 2 { return "", fmt.Errorf("unsupported reference: %s", refPath) } remoteComponent, flatComponent := pathParts[0], pathParts[1] - if goImport, ok := globalState.importMapping[remoteComponent]; !ok { + goPkg, ok := globalState.importMapping[remoteComponent] + + if !ok { return "", fmt.Errorf("unrecognized external reference '%s'; please provide the known import for this reference using option --import-mapping", remoteComponent) - } else { - goType, err := refPathToGoType("#"+flatComponent, false) - if err != nil { - return "", err + } + + if goPkg.Path == importMappingCurrentPackage { + return refPathToGoTypeSelf(fmt.Sprintf("#%s", pathParts[1]), local) + } + + return refPathToGoTypeRemote(flatComponent, goPkg) + +} + +func refPathToGoTypeSelf(refPath string, local bool) (string, error) { + pathParts := strings.Split(refPath, "/") + depth := len(pathParts) + if local { + if depth != 4 { + return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) } - return fmt.Sprintf("%s.%s", goImport.Name, goType), nil + } else if depth != 4 && depth != 2 { + return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) + } + + // 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. diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 7123f8f080..28f9f3f3dd 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -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", From b7b82be741ef532eb3f100fb61f62ca3da196ab9 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 20 Sep 2024 21:22:19 +0100 Subject: [PATCH 026/293] docs: correct wording of heading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bff27b3c4..b49d162f37 100644 --- a/README.md +++ b/README.md @@ -1893,7 +1893,7 @@ components: So how do we get `oapi-codegen` to generate our code? -### Using a single package, with multiple OpenAPI spec for a given package +### Using a single package with multiple OpenAPI specs From 7234c66fbed8ba6b6a063f360d2e7dc3aff03f3b Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 28 Sep 2024 11:16:33 +0100 Subject: [PATCH 027/293] docs(sponsors): clarify Elastic's 4h/mo This makes it a little bit clearer that Elastic's 4h/mo of in-work support that I'm able to do is different to the GitHub Sponsor'd support we receive from others. This isn't something that other sponsors can do right now, so we should make it clearer that Elastic's at a higher level. But we are _super appreciative_ of all of our sponsors! --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b49d162f37..89db9d7eb4 100644 --- a/README.md +++ b/README.md @@ -4136,7 +4136,19 @@ Please consider sponsoring us through GitHub Sponsors either [on the organisatio 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 currently sponsored for 4 hours of work a month by Elastic: + +

+ + + + + Elastic logo + + +

+ +In addition, we are also generously sponsored by the following folks, each of whom provide sponsorship for 1 hour of work a month:

@@ -4158,16 +4170,6 @@ We are currently generously sponsored by the following folks, each of whom provi

-

- - - - - Elastic logo - - -

-

Cybozu logo From 7ce53fab43ac6c61eb985c03cf07db30ada23c32 Mon Sep 17 00:00:00 2001 From: Ottavio Hartman Date: Sat, 28 Sep 2024 06:26:21 -0400 Subject: [PATCH 028/293] fix(import-mapping): don't produce unused variable when one mapping (#1781) As noted in #1779, we can sometimes lead to producing uncompilable code, when we have a single spec referenced with the import-mapping configuration to be the "self" - aka current - package. This leads to errors such as: gen.go:366:2: declared and not used: pathPrefix To handle this, we can inline the `.Dir()` call, so we don't conditionally have to set the variable. Closes #1779. --- internal/test/externalref/externalref.gen.go | 8 +++----- internal/test/externalref/packageA/externalref.gen.go | 4 +--- internal/test/externalref/petstore/externalref.gen.go | 4 +--- internal/test/issues/issue-1093/api/child/child.gen.go | 4 +--- internal/test/issues/issue-1182/pkg1/pkg1.gen.go | 4 +--- internal/test/issues/issue-1212/pkg1/pkg1.gen.go | 4 +--- internal/test/issues/issue-1378/bionicle/bionicle.gen.go | 4 +--- .../test/issues/issue-1378/fooservice/fooservice.gen.go | 6 ++---- pkg/codegen/templates/inline.tmpl | 5 +---- 9 files changed, 12 insertions(+), 31 deletions(-) diff --git a/internal/test/externalref/externalref.gen.go b/internal/test/externalref/externalref.gen.go index eee3f68f71..a1bd9f6ea2 100644 --- a/internal/test/externalref/externalref.gen.go +++ b/internal/test/externalref/externalref.gen.go @@ -76,21 +76,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 externalRef1.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 externalRef2.PathToRawSpec(path.Join(path.Dir(pathToFile), "https://petstore3.swagger.io/api/v3/openapi.json")) { if _, ok := res[rawPath]; ok { // it is not possible to compare functions in golang, so always overwrite the old value } diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go index c95790d770..582588326c 100644 --- a/internal/test/externalref/packageA/externalref.gen.go +++ b/internal/test/externalref/packageA/externalref.gen.go @@ -67,9 +67,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 } diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index c1d5d3e10d..33852217e1 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -298,9 +298,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 } 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..203fad36e8 100644 --- a/internal/test/issues/issue-1093/api/child/child.gen.go +++ b/internal/test/issues/issue-1093/api/child/child.gen.go @@ -188,9 +188,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 } diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index 7be0da44a6..0b01c5738e 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -386,9 +386,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 } diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index f817ec8376..c24850b199 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -399,9 +399,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 } diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index 9f6ffc8809..4af1127555 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -327,9 +327,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 } diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index c0542b6a55..6645be355e 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -320,15 +320,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 } diff --git a/pkg/codegen/templates/inline.tmpl b/pkg/codegen/templates/inline.tmpl index 851ea59b26..de00120502 100644 --- a/pkg/codegen/templates/inline.tmpl +++ b/pkg/codegen/templates/inline.tmpl @@ -40,11 +40,8 @@ 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 }}{{- if ne $value.Path "-"}} - for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(pathPrefix, "{{ $key }}")) { + 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 } From 9c09ef9e9d4be639bd3feff31ff2c06961421272 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 28 Sep 2024 11:29:52 +0100 Subject: [PATCH 029/293] build: relax patch version pinning on `go` directive Originally added in f77bd7b1b84a7f215eb43d4cecc1ba10927326ef, we wanted to pin the version to ensure that we were targeting the latest version of Go 1.21. However, there's no real value here, and as noted in [0] it can be causing issues for some users. There's nothing explicitly in Go 1.21.x that we need to pin to, just that we need support for Go 1.21, so we can use Speakeasy's `openapi-overlay` library. Therefore we can relax the patch-version requirement, which will alleviate issues for consumers. This makes sure that we have _at a minimum_ a version of Go 1.21, and makes `go mod tidy` happy. [0]: https://github.com/osbuild/image-builder/pull/1352 --- examples/go.mod | 2 +- go.mod | 2 +- internal/test/go.mod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 2066e1225f..b0d0f5012f 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.21.13 +go 1.21.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ diff --git a/go.mod b/go.mod index 7b15915468..58992dc1d9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.21.13 +go 1.21.0 require ( github.com/getkin/kin-openapi v0.127.0 diff --git a/internal/test/go.mod b/internal/test/go.mod index a3e01f4ec9..f04be07b47 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.21.13 +go 1.21.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ From 2b85cb44d2607f8ef27deaab67d367eb94301bdf Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 30 Sep 2024 15:27:19 +0100 Subject: [PATCH 030/293] docs: note the use of a multi-module `tools.go` --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 89db9d7eb4..c7b73fceb1 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ 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/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. From be6e3bec90ca5524cfe96b7d9b204f0aacb917b7 Mon Sep 17 00:00:00 2001 From: Ilango Date: Fri, 4 Oct 2024 22:08:26 +0530 Subject: [PATCH 031/293] docs: add blog post about using `oapi-codegen` in a Chi project (#1791) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c7b73fceb1..0592966463 100644 --- a/README.md +++ b/README.md @@ -3812,6 +3812,7 @@ 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! From 60f17b2844273fdee99a8078051d4a4ed4a63847 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 6 Oct 2024 20:52:20 +0100 Subject: [PATCH 032/293] docs: add contributors image --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0592966463..6cee104e2b 100644 --- a/README.md +++ b/README.md @@ -4129,12 +4129,18 @@ 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. +## Contributors + +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 💜 + + + + + ## 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. -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 💜 - 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. From 795989720d1cfe09f1de45ef0530e5ffa8cd29f8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:43:00 +0000 Subject: [PATCH 033/293] fix(deps): update module github.com/getkin/kin-openapi to v0.128.0 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 4 ++-- examples/go.mod | 2 +- examples/go.sum | 4 ++-- examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 2df22d9bdc..8b2dd7b88b 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.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 diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 06ae5d4617..d716b703e5 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/go.mod b/examples/go.mod index b0d0f5012f..fd45458d6b 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.21.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.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 diff --git a/examples/go.sum b/examples/go.sum index 786e67c039..7bfe6115e1 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -52,8 +52,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 41cde25da6..b18ec018ec 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -8,7 +8,7 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.127.0 // indirect + github.com/getkin/kin-openapi v0.128.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 diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 271a54f584..0b9d175881 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index b49ad323c4..6a2dfd3c1a 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.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 diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 1d7deb2f40..6bbec79617 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/go.mod b/go.mod index 58992dc1d9..577189827e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.21.0 require ( - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.0 github.com/speakeasy-api/openapi-overlay v0.9.0 github.com/stretchr/testify v1.9.0 golang.org/x/text v0.18.0 diff --git a/go.sum b/go.sum index 271a54f584..0b9d175881 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index f04be07b47..481fb90a1d 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.21.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 05f5fecaa5..012cc4b6f2 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -51,8 +51,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 24161ac4e0..bb205b92ee 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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.127.0 + github.com/getkin/kin-openapi v0.128.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 diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 1c76fe6548..a2e67218b4 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= 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= From fd1f9b3e448846c1c4749f5c7eaae60e2be7a02c Mon Sep 17 00:00:00 2001 From: Alexey Palazhchenko Date: Thu, 10 Oct 2024 19:24:47 +0400 Subject: [PATCH 034/293] docs: fix typo in flags usage #1796 --- cmd/oapi-codegen/oapi-codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 2d05cff92c..29a1b48bde 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -111,7 +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(&flagAliasTypes, "alias-types", false, "Alias type declarations if possible.") flag.BoolVar(&flagInitialismOverrides, "initialism-overrides", false, "Use initialism overrides.") flag.Parse() From 18c9887189108ed0ebb10df5603cbc73a9a78c81 Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Tue, 5 Nov 2024 00:40:14 +1100 Subject: [PATCH 035/293] fix(codegen): handle leading underscores in property names (#1822) Similar to other changes we've made to make our generated field names more predictable - and in many cases, valid Go names - we should tweak how a leading underscore is used in a field name. This avoids cases with a spec such as: ```yaml properties: _version: type: string version: type: int ``` Which would previously generate duplicate field names, `Version` and `Version`. Instead, we now produce `_Version` and `Version`. Co-authored-by: Jamie Tanna --- .../issue-illegal_enum_names/issue.gen.go | 20 +++++++++---------- .../issue-illegal_enum_names/issue_test.go | 2 +- pkg/codegen/utils.go | 2 ++ pkg/codegen/utils_test.go | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) 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..8f907486cf 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -22,16 +22,16 @@ 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_" ) // Bar defines model for Bar. 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..77d4eb416c 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue_test.go +++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go @@ -54,6 +54,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/pkg/codegen/utils.go b/pkg/codegen/utils.go index e82d5e3e3c..523c58941d 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -805,6 +805,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) { diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 28f9f3f3dd..b7a7318924 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -599,7 +599,7 @@ func TestSchemaNameToTypeName(t *testing.T) { "@timestamp,": "Timestamp", "&now": "AndNow", "~": "Tilde", - "_foo": "Foo", + "_foo": "UnderscoreFoo", "=3": "Equal3", "#Tag": "HashTag", ".com": "DotCom", From 31ff0f90065cdbacfba04bb3de12753e0cefa667 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:37:23 +0000 Subject: [PATCH 036/293] chore(deps): update module github.com/golangci/golangci-lint to v1.62.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 73e1cd3ac1..c6b1794256 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.61.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.62.2 .PHONY: tools tools: $(GOBIN)/golangci-lint From c77565aa01bbdeee5645ade39734ce35a330336f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 13:18:27 +0000 Subject: [PATCH 037/293] fix(deps): update module github.com/stretchr/testify to v1.10.0 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 3 ++- examples/go.mod | 2 +- examples/go.sum | 3 ++- examples/minimal-server/stdhttp/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 13 files changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 8b2dd7b88b..8fe50dffdc 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( 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 + github.com/stretchr/testify v1.10.0 ) require ( diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index d716b703e5..21b2bec201 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -114,8 +114,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/go.mod b/examples/go.mod index fd45458d6b..645fcc57fe 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,7 +22,7 @@ require ( 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 + github.com/stretchr/testify v1.10.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 ) diff --git a/examples/go.sum b/examples/go.sum index 7bfe6115e1..040435db73 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -266,8 +266,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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= diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 0b9d175881..629bc79a45 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -81,8 +81,8 @@ github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 6a2dfd3c1a..d8e684031c 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( 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 + github.com/stretchr/testify v1.10.0 ) require ( diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 6bbec79617..affec60f70 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -98,8 +98,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/go.mod b/go.mod index 577189827e..bde7f68483 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21.0 require ( github.com/getkin/kin-openapi v0.128.0 github.com/speakeasy-api/openapi-overlay v0.9.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 golang.org/x/text v0.18.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 0b9d175881..629bc79a45 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,8 @@ github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/internal/test/go.mod b/internal/test/go.mod index 481fb90a1d..ceb361ab2a 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -16,7 +16,7 @@ require ( 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 + github.com/stretchr/testify v1.10.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/internal/test/go.sum b/internal/test/go.sum index 012cc4b6f2..d3d93591bb 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -246,8 +246,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index bb205b92ee..ad65b3a1f2 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -12,7 +12,7 @@ require ( 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 + github.com/stretchr/testify v1.10.0 ) require ( diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index a2e67218b4..1436fea0bc 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -94,8 +94,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= From f010cb7971fa5615231546759863e939f9e4f238 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 07:45:56 +0000 Subject: [PATCH 038/293] fix(deps): update module golang.org/x/text to v0.20.0 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 8 ++++---- examples/go.mod | 2 +- examples/go.sum | 8 ++++---- examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 8 ++++---- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 8 ++++---- go.mod | 2 +- go.sum | 8 ++++---- internal/test/go.mod | 2 +- internal/test/go.sum | 8 ++++---- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 8 ++++---- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 8fe50dffdc..e66d4374b5 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -37,7 +37,7 @@ require ( github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 21b2bec201..5f87feb67a 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -155,8 +155,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -192,8 +192,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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= diff --git a/examples/go.mod b/examples/go.mod index 645fcc57fe..a73a316fdc 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -109,7 +109,7 @@ require ( 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.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.34.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 040435db73..78a0fd77f4 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -350,8 +350,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -386,8 +386,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index b18ec018ec..9b14e36694 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -19,7 +19,7 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 629bc79a45..1f1cf692fa 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -106,8 +106,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -130,8 +130,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index d8e684031c..e29c76831e 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -30,7 +30,7 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index affec60f70..151cc6ec81 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -123,8 +123,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -147,8 +147,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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= diff --git a/go.mod b/go.mod index bde7f68483..914750e087 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/getkin/kin-openapi v0.128.0 github.com/speakeasy-api/openapi-overlay v0.9.0 github.com/stretchr/testify v1.10.0 - golang.org/x/text v0.18.0 + golang.org/x/text v0.20.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 629bc79a45..1f1cf692fa 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -130,8 +130,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index ceb361ab2a..d470e4ed6c 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -97,7 +97,7 @@ require ( 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.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index d3d93591bb..0a72a7349e 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -316,8 +316,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -348,8 +348,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index ad65b3a1f2..d161abd8d6 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -31,7 +31,7 @@ require ( github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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 index 1436fea0bc..721fb77345 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -119,8 +119,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -143,8 +143,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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= From d3a2029448254ffee6dcc0284dbd4aeb2e1cab60 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Thu, 28 Nov 2024 09:59:33 +0200 Subject: [PATCH 039/293] feat(output-options): add `yaml-tags` option (#1798) As noted in #1696, there are some APIs that may want to be able to use the generated models with both JSON and YAML. One option is to use `x-oapi-codegen-extra-tags`, for instance applied via an Overlay. Alternatively, we can add a new Output Option to generate YAML tags alongside our JSON tags. Closes #1696. Signed-off-by: Avi Deitcher Co-authored-by: Jamie Tanna --- configuration-schema.json | 4 ++++ .../test/outputoptions/yaml-tags/config.yaml | 8 +++++++ .../test/outputoptions/yaml-tags/generate.go | 3 +++ .../test/outputoptions/yaml-tags/spec.yaml | 24 +++++++++++++++++++ .../test/outputoptions/yaml-tags/yamltags.go | 13 ++++++++++ pkg/codegen/configuration.go | 3 +++ pkg/codegen/schema.go | 6 +++++ 7 files changed, 61 insertions(+) create mode 100644 internal/test/outputoptions/yaml-tags/config.yaml create mode 100644 internal/test/outputoptions/yaml-tags/generate.go create mode 100644 internal/test/outputoptions/yaml-tags/spec.yaml create mode 100644 internal/test/outputoptions/yaml-tags/yamltags.go diff --git a/configuration-schema.json b/configuration-schema.json index 745c07406c..1d034ec715 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -214,6 +214,10 @@ "required": [ "path" ] + }, + "yaml-tags": { + "type": "boolean", + "description": "Enable the generation of YAML tags for struct fields" } } }, 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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index c2d36f9df0..da9dd463c3 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -239,6 +239,9 @@ type OutputOptions struct { // 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"` } func (oo OutputOptions) Validate() map[string]string { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 2cef0023fe..f0054a8671 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -728,11 +728,17 @@ func GenFieldsFromProperties(props []Property) []string { if !omitEmpty { fieldTags["json"] = p.JsonFieldName + if globalState.options.OutputOptions.EnableYamlTags { + fieldTags["yaml"] = p.JsonFieldName + } if p.NeedsFormTag { fieldTags["form"] = p.JsonFieldName } } else { fieldTags["json"] = p.JsonFieldName + ",omitempty" + if globalState.options.OutputOptions.EnableYamlTags { + fieldTags["yaml"] = p.JsonFieldName + ",omitempty" + } if p.NeedsFormTag { fieldTags["form"] = p.JsonFieldName + ",omitempty" } From cc9726150cffda62f2894af49da14d54f4bd29c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Gr=C3=A4ger?= Date: Thu, 28 Nov 2024 10:30:14 +0100 Subject: [PATCH 040/293] fix(overlay): correctly resolve references after Overlay application (#1825) In cases where using an Overlay with External References, `oapi-codegen` would error with: encountered disallowed external reference And: Failed to serialize Overlay'd specification "...": error resolving reference "...": open ...: no such file or directory This is because we missed setting `IsExternalRefsAllowed` and indicating that there is a file reference with `LoadFromDataWithPath`. Co-authored-by: Jamie Tanna --- internal/test/issues/issue1825/config.yaml | 11 ++ internal/test/issues/issue1825/doc.go | 5 + .../test/issues/issue1825/issue1825.gen.go | 110 ++++++++++++++++++ internal/test/issues/issue1825/object_b.json | 5 + internal/test/issues/issue1825/overlay.yaml | 10 ++ .../test/issues/issue1825/overlay_test.go | 14 +++ .../issues/issue1825/packageA/config.yaml | 7 ++ .../test/issues/issue1825/packageA/doc.go | 3 + .../issue1825/packageA/externalref.gen.go | 100 ++++++++++++++++ .../test/issues/issue1825/packageA/spec.yaml | 6 + internal/test/issues/issue1825/spec/spec.yaml | 11 ++ pkg/util/loader.go | 8 +- 12 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 internal/test/issues/issue1825/config.yaml create mode 100644 internal/test/issues/issue1825/doc.go create mode 100644 internal/test/issues/issue1825/issue1825.gen.go create mode 100644 internal/test/issues/issue1825/object_b.json create mode 100644 internal/test/issues/issue1825/overlay.yaml create mode 100644 internal/test/issues/issue1825/overlay_test.go create mode 100644 internal/test/issues/issue1825/packageA/config.yaml create mode 100644 internal/test/issues/issue1825/packageA/doc.go create mode 100644 internal/test/issues/issue1825/packageA/externalref.gen.go create mode 100644 internal/test/issues/issue1825/packageA/spec.yaml create mode 100644 internal/test/issues/issue1825/spec/spec.yaml 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..679963f84c --- /dev/null +++ b/internal/test/issues/issue1825/issue1825.gen.go @@ -0,0 +1,110 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/4SP0U7DMAxF/8Xw2K2TeOvbxAfAH1Re6m2G1rESd2Ka8u/IWQcIkPaUWNf33OsLhDhp", + "FBLL0F0ghyNNWL/PUQxZKPmgKSolY6pS3L1RsB79/5hoDx08tN+gdqG0iuEdD7Tts1LoX6prC6W5AXb3", + "AF97pfxy4TCwcRQcX39UszRTA3ZWgm5Z97j/e/w5S3Aifxd/tsRy8GgPZ9nHKrKNrkIDJ0qZo1yHj1U8", + "URrxvELVkWm4EuZgc6LhJtbjlQSVoYOn9Wa9Ae9nR29QymcAAAD//5P9oGCQAQAA", +} + +// 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 + } + + 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 +} + +// 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/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..115a878fad --- /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 := GetSwagger() + 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..b2d5ca870b --- /dev/null +++ b/internal/test/issues/issue1825/packageA/externalref.gen.go @@ -0,0 +1,100 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/yTJwQ0CMQxE0V7mnApyowJqCNHAGm1sKzYHtNreUZa5zJfegW7DTakZqAeibxztyvvj", + "zZ63lT7NOVN4gbbB9fl1oiJyir5wrhWIPg1VP/teYE5tLqhAgbfc4i/nLwAA//+kHCeTdgAAAA==", +} + +// 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/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/pkg/util/loader.go b/pkg/util/loader.go index b10e594304..8c56cf211a 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "net/url" + "path/filepath" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -85,7 +86,12 @@ func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (s return nil, fmt.Errorf("Failed to serialize Overlay'd specification %#v: %v", opts.Path, err) } - swagger, err = openapi3.NewLoader().LoadFromData(b) + 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) } From 3b53c01ee0a37e674cb01b46eb2d6c58188eead2 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 09:42:25 +0000 Subject: [PATCH 041/293] build(labels): add autolabeller for "no `main` branch please" This follows setup from Renovate, as a project with a good setup we can follow. We'll add this for Issues, Discussions and PRs for now, even though this only directly applies to PRs. --- .github/label-actions.yml | 11 +++++++++++ .github/workflows/label-actions.yml | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/label-actions.yml create mode 100644 .github/workflows/label-actions.yml diff --git a/.github/label-actions.yml b/.github/label-actions.yml new file mode 100644 index 0000000000..9d5548b8d1 --- /dev/null +++ b/.github/label-actions.yml @@ -0,0 +1,11 @@ +'auto:no-head-branch': + comment: > + Thanks for the contribution! + + It looks like this PR was raised from the `main` branch. + + As per [our contributing guidelines](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#before-you-raise-a-pr), this can make it difficult for us to push changes to your fork - for instance to directly push a change to address a comment that we would raise, or to finalise changes before merge. + + Please re-raise the PR from a branch on your repository that isn't `main` / any protected branches. + + Thank you in advance 🙇🏼 diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml new file mode 100644 index 0000000000..ff95f0a0cc --- /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@102faf474a544be75fbaf4df54e73d3c515a0e65 # v4.0.1 + with: + github-token: ${{ github.token }} From 5f8302222c6e907b227dc0a4dd672f3eb4bcf8ae Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:18:25 +0000 Subject: [PATCH 042/293] docs(sponsors): add Livepeer --- .github/sponsors/livepeer-dark.svg | 16 ++++++++++++++++ .github/sponsors/livepeer-light.svg | 16 ++++++++++++++++ README.md | 10 ++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .github/sponsors/livepeer-dark.svg create mode 100644 .github/sponsors/livepeer-light.svg diff --git a/.github/sponsors/livepeer-dark.svg b/.github/sponsors/livepeer-dark.svg new file mode 100644 index 0000000000..2abe96ec95 --- /dev/null +++ b/.github/sponsors/livepeer-dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/.github/sponsors/livepeer-light.svg b/.github/sponsors/livepeer-light.svg new file mode 100644 index 0000000000..71b5a40b27 --- /dev/null +++ b/.github/sponsors/livepeer-light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 6cee104e2b..645ae06964 100644 --- a/README.md +++ b/README.md @@ -4185,4 +4185,14 @@ In addition, we are also generously sponsored by the following folks, each of wh

+

+ + + + + Livepeer logo + + +

+ (Note that the order of appearance the order in which sponsorship was received) From 2461df914706325624e84bcdccc31199b05b5521 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 11:36:10 +0000 Subject: [PATCH 043/293] build: ensure separately named "Check results" steps This makes sure these are now 4 separate checks, which can be independently added, which ensures that all stages run successfully before an auto-merge applies. Previously, we've had cases where a PR can be automerged before all checks execute, as GitHub sees that one of the `Check results` steps has passed, and expects all of them have. --- .github/workflows/ci.yml | 2 +- .github/workflows/generate.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tidy.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1d7d02d55..7b57f0be1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: results: if: ${{ always() }} runs-on: ubuntu-latest - name: Check results + name: Check build results needs: [build] steps: - run: | diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 588f63411e..51f8490a31 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -33,7 +33,7 @@ jobs: results: if: ${{ always() }} runs-on: ubuntu-latest - name: Check results + name: Check generation results needs: [build] steps: - run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 07cdf5d6c8..49c0b1a07f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,7 +30,7 @@ jobs: results: if: ${{ always() }} runs-on: ubuntu-latest - name: Check results + name: Check linting results needs: [build] steps: - run: | diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index cd96670676..7c661110b6 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -33,7 +33,7 @@ jobs: results: if: ${{ always() }} runs-on: ubuntu-latest - name: Check results + name: Check tidy results needs: [build] steps: - run: | From 38b8c5355c21ea7b4c96080ef5c961e11f0aabdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ch=C3=A1bek?= Date: Thu, 28 Nov 2024 13:06:13 +0100 Subject: [PATCH 044/293] feat(client): Add `Bytes()` to `ClientWithResponses` responses (#1780) As noted in #240, it may be useful to have a more convenient means to access the underlying bytes of a given response type, without using the `r.Body` field, we can introduce a new method, `Bytes()`. This convenience method should not be generated by default, as it introduces a large diff, and may not be expected, and is wired in with a new Output Option. Closes #240. Co-authored-by: Jamie Tanna --- configuration-schema.json | 4 + internal/test/issues/issue240/api.yaml | 47 +++ internal/test/issues/issue240/cfg.yaml | 8 + internal/test/issues/issue240/client.gen.go | 355 ++++++++++++++++++ internal/test/issues/issue240/generate.go | 3 + pkg/codegen/configuration.go | 3 + .../templates/client-with-responses.tmpl | 7 + 7 files changed, 427 insertions(+) create mode 100644 internal/test/issues/issue240/api.yaml create mode 100644 internal/test/issues/issue240/cfg.yaml create mode 100644 internal/test/issues/issue240/client.gen.go create mode 100644 internal/test/issues/issue240/generate.go diff --git a/configuration-schema.json b/configuration-schema.json index 1d034ec715..715ed83fa6 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -218,6 +218,10 @@ "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`" } } }, 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..8a0a533589 --- /dev/null +++ b/internal/test/issues/issue240/client.gen.go @@ -0,0 +1,355 @@ +// 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("GET", 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("PUT", 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 +} + +// 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 +} + +type UpdateClientResponse struct { + Body []byte + HTTPResponse *http.Response + JSON400 *struct { + Code string `json:"code"` + } +} + +// 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 +} + +// 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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index da9dd463c3..228626ad12 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -242,6 +242,9 @@ type OutputOptions struct { // 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"` } func (oo OutputOptions) Validate() map[string]string { diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index 908f21476a..3b85500a8d 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -74,6 +74,13 @@ 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}} {{end}} From b07f7ea6d520cd9eb12455e4ebc7db8b80246fc3 Mon Sep 17 00:00:00 2001 From: Micael Malta Date: Thu, 28 Nov 2024 08:08:30 -0500 Subject: [PATCH 045/293] feat: allow specifying `additional-initialisms` (#1733) As well as the inbuilt initialisms that are found in `oapi-codegen`, there are additional initialisms that shouldn't exist upstream as they are either contentious in the community or that are user- or organisation-specific. To handle this, we can introduce a new configuration option, `additional-initialisms`, for user-provided initialisms. We need to make sure that this provides an early indication of these settings being set incorrectly by failing early to indicate that the configuration isn't valid without using the `name-normalizer: ToCamelCaseWithInitialisms`. This also requires that we refactor the `initalismsMap` to pull this into the `globalState`, as it's now dependent on the configuration used, and this ensures that the settings are isolated. Co-authored-by: Jamie Tanna --- configuration-schema.json | 7 + .../config.yaml | 13 + .../generate.go | 3 + .../name_normalizer.gen.go | 590 ++++++++++++++++++ .../name_normalizer_test.go | 24 + pkg/codegen/codegen.go | 9 + pkg/codegen/configuration.go | 9 + pkg/codegen/utils.go | 21 +- 8 files changed, 668 insertions(+), 8 deletions(-) create mode 100644 internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/config.yaml create mode 100644 internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/generate.go create mode 100644 internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go create mode 100644 internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer_test.go diff --git a/configuration-schema.json b/configuration-schema.json index 715ed83fa6..2b15fe56cb 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -173,6 +173,13 @@ "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" + } + }, "nullable-type": { "type": "boolean", "description": "Whether to generate nullable type for nullable fields" 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..b04b92ae87 --- /dev/null +++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go @@ -0,0 +1,590 @@ +// 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/gzip" + "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.StyleParamWithLocation("simple", false, "petId", runtime.ParamLocationPath, petID) + 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("GET", 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 +} + +// 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 +} + +// 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 + + // ------------- Path parameter "petId" ------------- + var petID string + + err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petID, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + 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("GET") + + return r +} + +// Base64 encoded, gzipped, json marshaled Swagger object +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 +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/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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 632f649e23..ef175afdd5 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -47,6 +47,9 @@ 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 } // goImport represents a go package to be imported in the generated code @@ -139,6 +142,12 @@ 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) + // This creates the golang templates text package TemplateFunctions["opts"] = func() Configuration { return globalState.options } t := template.New("oapi-codegen").Funcs(TemplateFunctions) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 228626ad12..89acddc211 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -226,6 +226,9 @@ type OutputOptions struct { 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"` // Whether to generate nullable type for nullable fields NullableType bool `yaml:"nullable-type,omitempty"` @@ -248,6 +251,12 @@ type OutputOptions struct { } func (oo OutputOptions) Validate() map[string]string { + if NameNormalizerFunction(oo.NameNormalizer) != NameNormalizerFunctionToCamelCaseWithInitialisms && len(oo.AdditionalInitialisms) > 0 { + return map[string]string{ + "additional-initialisms": "You have specified `additional-initialisms`, but the `name-normalizer` is not set to `ToCamelCaseWithInitialisms`. Please specify `name-normalizer: ToCamelCaseWithInitialisms` or remove the `additional-initialisms` configuration", + } + } + return nil } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 523c58941d..ee89c75011 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -283,7 +283,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 +292,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 +322,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])) { From cf6d2416f5e202a0b2822ce24189ab72e5c50192 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 09:57:16 +0000 Subject: [PATCH 046/293] build(labels): add "no-mentions" --- .github/label-actions.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/label-actions.yml b/.github/label-actions.yml index 9d5548b8d1..9e80c3ec13 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -9,3 +9,17 @@ Please re-raise the PR from a branch on your repository that isn't `main` / any protected branches. Thank you in advance 🙇🏼 + +'auto:no-mentions': + comment: > + Thanks for your use of `oapi-codegen`! + + We are very appreciative of your interest in improving the project, and that you're engaged with us. + + However, @-mentioning the maintainers will be very unlikely to help move your issue along, and we do not want to encourage behaviour that leads to the "noisiest" users getting the benefit over folks who are waiting their turn. + + Please remember that `oapi-codegen` is for the most part run by volunteers, and [we have a request out](https://github.com/oapi-codegen/oapi-codegen/discussions/1606) to companies who use the project to help make it more sustainable, with sponsorship. + + It will only be that sustained financial support will be able to make it possible to work more efficiently towards user requests. + + For more info on engaging with the maintainers, see [our CONTRIBUTING guide](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#should-i--mention-the-maintainers-on-an-issue). From 1b9c32e66072fbc31ad75fbf9ae7eb51acd8bc2e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:00:28 +0000 Subject: [PATCH 047/293] build(labels): add "pinning-until-next-release" --- .github/label-actions.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/label-actions.yml b/.github/label-actions.yml index 9e80c3ec13..1d307b6304 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -23,3 +23,7 @@ It will only be that sustained financial support will be able to make it possible to work more efficiently towards user requests. For more info on engaging with the maintainers, see [our CONTRIBUTING guide](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#should-i--mention-the-maintainers-on-an-issue). + +'auto:pinning-until-release': + comment: > + [Until there is a defined release cadence planned](https://github.com/oapi-codegen/oapi-codegen/issues/1519), our [official recommendation](https://github.com/oapi-codegen/oapi-codegen/blob/main/README.md#pinning-to-commits) is that you pin to the latest commit on `main`, which will allow you to pull in this change. From 344a17bfd1daf3790b4961a45d5f1640d70f951c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:09:29 +0000 Subject: [PATCH 048/293] build(labels): auto-label `main` PRs --- .github/labeler.yml | 3 +++ .github/workflows/labeler.yml | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/labeler.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..792590af6e --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,3 @@ +'auto:no-head-branch': +- head-branch: + - '^main$' diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..e57cd86e2b --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 From 1bcf7de63d27421f7be99412771ed6f59ca93c78 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:15:42 +0000 Subject: [PATCH 049/293] build(labels): add "sponsorship" --- .github/label-actions.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/label-actions.yml b/.github/label-actions.yml index 1d307b6304..f3424d8057 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -27,3 +27,13 @@ 'auto:pinning-until-release': comment: > [Until there is a defined release cadence planned](https://github.com/oapi-codegen/oapi-codegen/issues/1519), our [official recommendation](https://github.com/oapi-codegen/oapi-codegen/blob/main/README.md#pinning-to-commits) is that you pin to the latest commit on `main`, which will allow you to pull in this change. + +'auto:sponsorship': + comment: > + Please remember that `oapi-codegen` is for the most part run by volunteers, and [we have a request out](https://github.com/oapi-codegen/oapi-codegen/discussions/1606) to companies who use the project to help make it more sustainable, with sponsorship. + + If this is high-priority for your organisation, please consider whether you would like to sponsor ongoing maintenance of the project, or that you may want to engage the maintainers to perform a one-off contract/bug bounty. + + Also remember that although it can seem like "just" a "small change", the maintainers are on the hook for maintaining the changes: + + > [No is temporary, yes is forever](https://www.oreilly.com/library/view/hands-on-design-patterns/9781789135565/3f396314-dac8-446c-ab02-768ae91296fa.xhtml) From 7fc764e0eb9d57eca62ab7e84fda2bf36de389fe Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:56:54 +0000 Subject: [PATCH 050/293] docs(contributing): add stronger about Apache-2.0'ing minimal repro --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3674b1cf16..6c4205ae6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: From 9feb3033b6127185b7d89e240bcf5471bf8328f4 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 28 Nov 2024 10:57:29 +0000 Subject: [PATCH 051/293] build(labels): add "reproduction:needed" --- .github/label-actions.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/label-actions.yml b/.github/label-actions.yml index f3424d8057..342da5bb30 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -37,3 +37,13 @@ Also remember that although it can seem like "just" a "small change", the maintainers are on the hook for maintaining the changes: > [No is temporary, yes is forever](https://www.oreilly.com/library/view/hands-on-design-patterns/9781789135565/3f396314-dac8-446c-ab02-768ae91296fa.xhtml) + +'reproduction:needed': + comment: > + Thanks for the report! + + To help maintainers (or other users) help with triaging and fixing of the issue more easily, we need a [Minimal Reproduction](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#minimal-reproductions) test case. + + Please follow the instructions, and then share a URL to the repository. + + We will not accept `.zip` files as reproductions, sorry! From 8bbe226927c98d11457cb125d3eaf82589022e7f Mon Sep 17 00:00:00 2001 From: Chai Landau <112015853+chailandau@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:25:41 -0500 Subject: [PATCH 052/293] docs(sponsors): update speakeasy sponsor graphic (#1874) --- .github/sponsors/speakeasy-dark.svg | 38 +++++++++++++--------------- .github/sponsors/speakeasy-light.svg | 38 +++++++++++++--------------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/.github/sponsors/speakeasy-dark.svg b/.github/sponsors/speakeasy-dark.svg index 7c4eba28a1..bfcf4990e2 100644 --- a/.github/sponsors/speakeasy-dark.svg +++ b/.github/sponsors/speakeasy-dark.svg @@ -1,25 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + - - + + diff --git a/.github/sponsors/speakeasy-light.svg b/.github/sponsors/speakeasy-light.svg index fd179ec617..59ec648f4a 100644 --- a/.github/sponsors/speakeasy-light.svg +++ b/.github/sponsors/speakeasy-light.svg @@ -1,25 +1,23 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + - - + + From 563099466132a8972af1f25d1fa9b00352ae2a2f Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 12 Feb 2025 09:57:05 +0000 Subject: [PATCH 053/293] build: build against Go 1.24 Now it's out, we should make sure folks using the project on the newest version are still supported. --- .github/workflows/ci.yml | 1 + .github/workflows/generate.yml | 1 + .github/workflows/lint.yml | 1 + .github/workflows/tidy.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b57f0be1a..944fbf73b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: - "1.21" - "1.22" - "1.23" + - "1.24" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 51f8490a31..7b8cfa2062 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -12,6 +12,7 @@ jobs: - "1.21" - "1.22" - "1.23" + - "1.24" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 49c0b1a07f..7de6fe42aa 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,6 +12,7 @@ jobs: - "1.21" - "1.22" - "1.23" + - "1.24" steps: - name: Check out source code uses: actions/checkout@v4 diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 7c661110b6..61a11b8c24 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -12,6 +12,7 @@ jobs: - "1.21" - "1.22" - "1.23" + - "1.24" steps: - name: Check out source code uses: actions/checkout@v4 From 2647a108f5fd2efaa11e398f596361331830bc5a Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 20 Feb 2025 15:30:15 +0000 Subject: [PATCH 054/293] docs: add example of using `go tool` for Go 1.24+ --- README.md | 19 ++ .../minimal-server/stdhttp-go-tool/Makefile | 36 ++++ .../stdhttp-go-tool/api/cfg.yaml | 6 + .../stdhttp-go-tool/api/generate.go | 3 + .../stdhttp-go-tool/api/impl.go | 25 +++ .../stdhttp-go-tool/api/ping.gen.go | 171 ++++++++++++++++++ .../minimal-server/stdhttp-go-tool/go.mod | 27 +++ .../minimal-server/stdhttp-go-tool/go.sum | 168 +++++++++++++++++ .../minimal-server/stdhttp-go-tool/main.go | 26 +++ 9 files changed, 481 insertions(+) create mode 100644 examples/minimal-server/stdhttp-go-tool/Makefile create mode 100644 examples/minimal-server/stdhttp-go-tool/api/cfg.yaml create mode 100644 examples/minimal-server/stdhttp-go-tool/api/generate.go create mode 100644 examples/minimal-server/stdhttp-go-tool/api/impl.go create mode 100644 examples/minimal-server/stdhttp-go-tool/api/ping.gen.go create mode 100644 examples/minimal-server/stdhttp-go-tool/go.mod create mode 100644 examples/minimal-server/stdhttp-go-tool/go.sum create mode 100644 examples/minimal-server/stdhttp-go-tool/main.go diff --git a/README.md b/README.md index 645ae06964..d153fd7d10 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,25 @@ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest ## Install +## For Go 1.24+ + +It is recommended to follow [the `go tool` support available from Go 1.24+](https://www.jvt.me/posts/2025/01/27/go-tools-124/) for managing the dependency of `oapi-codegen` alongside your core application. + +To do this, you run `go get -tool`: + +```sh +$ go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest +# this will then modify your `go.mod` +``` + +From there, each invocation of `oapi-codegen` would be used like so: + +```go +//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml +``` + +## Prior to Go 1.24 + 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`: diff --git a/examples/minimal-server/stdhttp-go-tool/Makefile b/examples/minimal-server/stdhttp-go-tool/Makefile new file mode 100644 index 0000000000..a25a6994c9 --- /dev/null +++ b/examples/minimal-server/stdhttp-go-tool/Makefile @@ -0,0 +1,36 @@ +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-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) 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..9e6c44cd0c --- /dev/null +++ b/examples/minimal-server/stdhttp-go-tool/api/generate.go @@ -0,0 +1,3 @@ +package api + +//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/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..794f8d817f --- /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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +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("GET "+options.BaseURL+"/ping", wrapper.GetPing) + + return m +} diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod new file mode 100644 index 0000000000..66174f2553 --- /dev/null +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -0,0 +1,27 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp-go-tool + +go 1.22 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/getkin/kin-openapi v0.128.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/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // 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-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum new file mode 100644 index 0000000000..1f1cf692fa --- /dev/null +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -0,0 +1,168 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/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/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.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/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/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/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/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +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/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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +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/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()) +} From 12f499350f6e0ae7b00d4ed360018bf548d19b16 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:34:24 +0000 Subject: [PATCH 055/293] chore(deps): update module github.com/golangci/golangci-lint to v1.64.5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c6b1794256..aca6de83eb 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.62.2 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.64.5 .PHONY: tools tools: $(GOBIN)/golangci-lint From 141a199381af5f8e4529ce4e7cb1d07438371f37 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 14 Mar 2025 22:08:45 +0000 Subject: [PATCH 056/293] chore: don't use non-GitHub URL for tests As we shouldn't be relying on a service we don't support, especially as right now it's returning HTTP 403s. --- cmd/oapi-codegen/oapi-codegen_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From 4912cb8a1654eb1a056bb08e5a0fb461f9fed194 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Sat, 15 Mar 2025 06:15:28 +0800 Subject: [PATCH 057/293] docs: simplify go tool example (#1910) Co-authored-by: Jamie Tanna --- README.md | 2 +- examples/minimal-server/stdhttp-go-tool/api/generate.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d153fd7d10..7172190ea9 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ $ go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest From there, each invocation of `oapi-codegen` would be used like so: ```go -//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml +//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml ``` ## Prior to Go 1.24 diff --git a/examples/minimal-server/stdhttp-go-tool/api/generate.go b/examples/minimal-server/stdhttp-go-tool/api/generate.go index 9e6c44cd0c..8b01fe5ccc 100644 --- a/examples/minimal-server/stdhttp-go-tool/api/generate.go +++ b/examples/minimal-server/stdhttp-go-tool/api/generate.go @@ -1,3 +1,3 @@ package api -//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml +//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml From 1ab2a1b72c0cdd9c97b311f0f8164022878c4cfa Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 14 Mar 2025 22:05:21 +0000 Subject: [PATCH 058/293] chore(examples): use Go 1.24 with Go 1.24 example Co-authored-by: Gaiaz Iusipov --- examples/minimal-server/stdhttp-go-tool/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 66174f2553..6377b05f65 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp-go-tool -go 1.22 +go 1.24 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ From cbcd935b5d9631564bdc4e3a278042ff23fecd2a Mon Sep 17 00:00:00 2001 From: Marvin Wendt Date: Thu, 20 Mar 2025 17:19:36 +0100 Subject: [PATCH 059/293] docs: fix GitHub flavoured markdown (#1934) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7172190ea9..3642cdbe20 100644 --- a/README.md +++ b/README.md @@ -3188,7 +3188,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 From bfc3a84b4950d9390486e9f95cb88303c18cdc9b Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 7 Apr 2025 10:05:00 +0100 Subject: [PATCH 060/293] chore(codegen): reword comment --- pkg/codegen/operations.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 3b0f130162..c6c388423f 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -208,7 +208,8 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen // 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 PathParams []ParameterDefinition // Parameters in the path, eg, /path/:param HeaderParams []ParameterDefinition // Parameters in HTTP headers From 1883b30943aef47e6ef92d417517e3fee0d97165 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 7 Apr 2025 10:05:22 +0100 Subject: [PATCH 061/293] fix(codegen): allow exposing the input spec's `operationId` As noted in #1274, there appears to be a modification of the underlying `operationId` in a given Operation, which is leading to the Embedded Spec getting a different `operationId` than our input specification. This appears to be due to the reference to the `Operation` being modified (unintentionally, it would seem) in `OperationDefinitions`, resulting in a `nameNormalizer`'d `operationId` being emitted, instead of the input specification's `operationId`. We can make sure that this is documented behaviour for the future, for anyone else modifying this file. To allow users to modify this, we can introduce an opt-in Compatibility flag, `preserve-original-operation-id-casing-in-embedded-spec`. Although this would be ideally an opt-out, this has the risk of breaking existing code, so we can't push it to users. To make sure that the underlying `operationId` isn't (always) modified, we can take a copy of the value and then only update it if it's not opted-out. This also wires in a new test-case to document behaviour and to catch issues in the future. Closes #1274. --- configuration-schema.json | 4 + .../api.yaml | 24 +++++ .../cfg.yaml | 9 ++ .../generate.go | 3 + .../spec.gen.go | 97 +++++++++++++++++++ .../spec_test.go | 29 ++++++ pkg/codegen/configuration.go | 8 ++ pkg/codegen/operations.go | 25 +++-- 8 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/api.yaml create mode 100644 internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/cfg.yaml create mode 100644 internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/generate.go create mode 100644 internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec.gen.go create mode 100644 internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec_test.go diff --git a/configuration-schema.json b/configuration-schema.json index 2b15fe56cb..53cfc64b95 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -103,6 +103,10 @@ "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." } } }, 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..030c8277d9 --- /dev/null +++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec.gen.go @@ -0,0 +1,97 @@ +// 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/gzip" + "encoding/base64" + "fmt" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" +) + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/7SOwUrFQAxFf0Xuevpe1d3sHuJCBBH8AJnXxjbaZkIThFLm32XGlR9gNjcEcu45wPKR", + "EQ84+0KIWPcbUxoQ8E2bcRZE3J76U48SkJUkKSPivp0CNPls9f+s5DVHWsipbllpS85ZnkZE+MzWsXWp", + "+6Jrul5kfEgrLe9vL5fnRwRsZJrFqMHu+r7GkMVJGjapLjw03PnTqtUBG2ZaU5PftbqbbywTSpuA6dfo", + "r8dE/kr+H4WllJ8AAAD//+CJBDdPAQAA", +} + +// 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/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..2f395b5776 --- /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 := GetSwagger() + 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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 89acddc211..644ead359f 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -195,6 +195,14 @@ 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"` } func (co CompatibilityOptions) Validate() map[string]string { diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index c6c388423f..dd6b913b3d 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -559,25 +559,34 @@ 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 // 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, toCamelCaseFunc) 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 + + if !globalState.options.Compatibility.PreserveOriginalOperationIdCasingInEmbeddedSpec { + // update the existing, shared, copy of the spec if we're not wanting to preserve it + 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) @@ -600,14 +609,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) 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()) if err != nil { return nil, fmt.Errorf("error generating response definitions: %w", err) } @@ -619,7 +628,7 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper HeaderParams: FilterParameterDefinitionByType(allParams, "header"), QueryParams: FilterParameterDefinitionByType(allParams, "query"), CookieParams: FilterParameterDefinitionByType(allParams, "cookie"), - OperationId: nameNormalizer(op.OperationID), + OperationId: nameNormalizer(operationId), // Replace newlines in summary. Summary: op.Summary, Method: opName, From c8859a425cc192d651e823969f14b9ca270a7cdb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:27:33 +0000 Subject: [PATCH 062/293] chore(deps): pin dependencies --- .github/workflows/ci.yml | 4 ++-- .github/workflows/generate.yml | 4 ++-- .github/workflows/labeler.yml | 2 +- .github/workflows/lint.yml | 4 ++-- .github/workflows/release-drafter.yml | 2 +- .github/workflows/tidy.yml | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 944fbf73b2..84a0d54854 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,10 @@ jobs: - "1.24" steps: - name: Check out source code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 7b8cfa2062..206ad19861 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -15,10 +15,10 @@ jobs: - "1.24" steps: - name: Check out source code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index e57cd86e2b..b1cdfcf47d 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,4 +9,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7de6fe42aa..fa96d2ed6f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,10 +15,10 @@ jobs: - "1.24" steps: - name: Check out source code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 9e02696343..b71effb618 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@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6 with: name: next tag: next diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 61a11b8c24..2868fe170e 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -15,10 +15,10 @@ jobs: - "1.24" steps: - name: Check out source code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 with: go-version: ${{ matrix.version }} From a5ab570046ffee040c2c0da62eef3389707aa0b2 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 14 Apr 2025 15:29:13 +0100 Subject: [PATCH 063/293] docs(middleware): clarify use of `nethttp-middleware` for other purposes --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 3642cdbe20..bdd4ffce28 100644 --- a/README.md +++ b/README.md @@ -3106,6 +3106,20 @@ Middleware library +
+ + +Any other server (which conforms to `net/http`) + + + + +[nethttp-middleware](https://github.com/oapi-codegen/nethttp-middleware) + + + +
+ > [!NOTE] From 5b718542d5c454b90d3ef436f19c53eca3e67d03 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 14 Apr 2025 20:48:28 +0100 Subject: [PATCH 064/293] fix(stdhttp): correctly generate root paths As noted in #1952, using the root path for a given path doesn't get correctly converted to the end-of-URL matcher, so we're accidentally creating a matcher for /all/ URLs, which is invalid. We can add a special case handler for the root path, and return the expected wildcard alternatively. Closes #1952. --- pkg/codegen/utils.go | 6 ++++++ pkg/codegen/utils_test.go | 1 + 2 files changed, 7 insertions(+) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index ee89c75011..962b967505 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -628,6 +628,12 @@ func SwaggerUriToGorillaUri(uri string) string { // {?param} // {?param*} func SwaggerUriToStdHttpUri(uri string) string { + // https://pkg.go.dev/net/http#hdr-Patterns-ServeMux + // The special wildcard {$} matches only the end of the URL. For example, the pattern "/{$}" matches only the path "/", whereas the pattern "/" matches every path. + if uri == "/" { + return "/{$}" + } + return pathParamRE.ReplaceAllString(uri, "{$1}") } diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index b7a7318924..af71438473 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -439,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}")) From e6bcad1155e7d1dd0865caf2e9819cfdca6de79f Mon Sep 17 00:00:00 2001 From: ignassew <56316914+ignassew@users.noreply.github.com> Date: Mon, 21 Apr 2025 17:16:40 +0200 Subject: [PATCH 065/293] fix: print the warning message to stderr instead of stdout (#1895) Co-authored-by: Jamie Tanna --- cmd/oapi-codegen/oapi-codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 29a1b48bde..7098f4d740 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -297,7 +297,7 @@ func main() { } 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/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") + 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 { From 0e8156a14e1a92e59194230873b2053d5b29e38b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 19:40:41 +0000 Subject: [PATCH 066/293] fix(deps)!: update module github.com/speakeasy-api/openapi-overlay to v0.10.1 This is flagged as a breaking change as it could break consumers, as `github.com/speakeasy-api/jsonpath` requires a minimum source compatibility (via `go`) of 1.22. This is still a deprecated version of Go (which ran out of support on 2025-02-11), so is still outdated, and therefore shouldn't be /that/ breaking. However, we should make it clear. This also requires we remove Go 1.21 from our CI, as it's no longer supported. --- .github/workflows/ci.yml | 1 - .github/workflows/generate.yml | 1 - .github/workflows/lint.yml | 1 - .github/workflows/tidy.yml | 1 - examples/authenticated-api/stdhttp/go.mod | 3 ++- examples/authenticated-api/stdhttp/go.sum | 11 +++++------ examples/go.mod | 5 +++-- examples/go.sum | 9 +++++---- examples/minimal-server/stdhttp-go-tool/go.mod | 3 ++- examples/minimal-server/stdhttp-go-tool/go.sum | 11 +++++------ examples/minimal-server/stdhttp/go.mod | 3 ++- examples/minimal-server/stdhttp/go.sum | 11 +++++------ examples/petstore-expanded/stdhttp/go.mod | 3 ++- examples/petstore-expanded/stdhttp/go.sum | 11 +++++------ go.mod | 5 +++-- go.sum | 11 +++++------ internal/test/go.mod | 5 +++-- internal/test/go.sum | 9 +++++---- internal/test/strict-server/stdhttp/go.mod | 3 ++- internal/test/strict-server/stdhttp/go.sum | 11 +++++------ 20 files changed, 59 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84a0d54854..384384f6b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,6 @@ jobs: # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go matrix: version: - - "1.21" - "1.22" - "1.23" - "1.24" diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 206ad19861..b35720292f 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -9,7 +9,6 @@ jobs: # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go matrix: version: - - "1.21" - "1.22" - "1.23" - "1.24" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fa96d2ed6f..c7748f399e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,6 @@ jobs: # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go matrix: version: - - "1.21" - "1.22" - "1.23" - "1.24" diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 2868fe170e..f01e12f961 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -9,7 +9,6 @@ jobs: # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go matrix: version: - - "1.21" - "1.22" - "1.23" - "1.24" diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index e66d4374b5..e808d10f40 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -33,7 +33,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.17.0 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 5f87feb67a..f436fbe0bc 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -37,8 +37,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= @@ -89,9 +87,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -102,8 +99,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/go.mod b/examples/go.mod index a73a316fdc..0b4da16308 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.21.0 +go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ @@ -91,7 +91,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect - github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/tdewolff/minify/v2 v2.12.9 // indirect github.com/tdewolff/parse/v2 v2.6.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 78a0fd77f4..bdc31d6292 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -223,9 +223,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -249,8 +248,10 @@ 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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 6377b05f65..7334634331 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -17,7 +17,8 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index 1f1cf692fa..39478df520 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -32,8 +32,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -65,9 +63,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -76,8 +73,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 9b14e36694..f0e5063363 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -16,7 +16,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 1f1cf692fa..39478df520 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -32,8 +32,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -65,9 +63,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -76,8 +73,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index e29c76831e..cd7e03907c 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -27,7 +27,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 151cc6ec81..aaebd5a0dd 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -36,8 +36,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -80,9 +78,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -91,8 +88,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/go.mod b/go.mod index 914750e087..c962eb2d68 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.21.0 +go 1.22 require ( github.com/getkin/kin-openapi v0.128.0 - github.com/speakeasy-api/openapi-overlay v0.9.0 + github.com/speakeasy-api/openapi-overlay v0.10.1 github.com/stretchr/testify v1.10.0 golang.org/x/text v0.20.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d @@ -23,6 +23,7 @@ require ( 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/speakeasy-api/jsonpath v0.6.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect diff --git a/go.sum b/go.sum index 1f1cf692fa..39478df520 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -65,9 +63,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -76,8 +73,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index d470e4ed6c..f8cc46e28a 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.21.0 +go 1.22 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ @@ -78,7 +78,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect - github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // 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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 0a72a7349e..752fd496c8 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -203,9 +203,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -227,8 +226,10 @@ 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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index d161abd8d6..5813694fbb 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -28,7 +28,8 @@ require ( 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/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 721fb77345..0a34b1cbdf 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -36,8 +36,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -76,9 +74,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa 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/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -87,8 +84,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= -github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= +github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= From 7e420aec898a8f661e7cea3338ed15539076b54e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 4 May 2025 19:42:39 +0100 Subject: [PATCH 067/293] docs: be explicit about OpenAPI 3.1 support --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index bdd4ffce28..1bfd4510c9 100644 --- a/README.md +++ b/README.md @@ -3851,6 +3851,12 @@ 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). + ### How does `oapi-codegen` handle `anyOf`, `allOf` and `oneOf`? `oapi-codegen` supports `anyOf`, `allOf` and `oneOf` for generated code. From 85c4b48c271ebf12cd8c6dfe24e8342c0885bfb6 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 4 May 2025 19:43:23 +0100 Subject: [PATCH 068/293] docs: add clarification title for Overlay To improve searching. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1bfd4510c9..39fcd4db62 100644 --- a/README.md +++ b/README.md @@ -2037,7 +2037,7 @@ If you don't want to do this, an alternate option is to [use a single package, w Check out [the import-mapping/multiplepackages example](examples/import-mapping/multiplepackages/) for the full code. -## Modifying the input OpenAPI Specification +## 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. From e62b97626b650eb1564a8e4bc21881d43fb88932 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 4 May 2025 19:44:56 +0100 Subject: [PATCH 069/293] docs: add example for how to downgrade OpenAPI 3.1 to 3.0 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 39fcd4db62..42ac2f336b 100644 --- a/README.md +++ b/README.md @@ -3857,6 +3857,8 @@ 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. From b4a1b00c6a0829a621ef1ca9ed59385c165baae5 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 7 May 2025 08:05:54 +0100 Subject: [PATCH 070/293] chore(tests): add test case for `x-go-type` and `-skip-optional-pointer` As part of future changes, we'll be modifying the way this works, so we should capture the current behaviour. --- internal/test/go.mod | 2 +- internal/test/issues/issue1957/config.yaml | 6 ++ internal/test/issues/issue1957/generate.go | 3 + .../test/issues/issue1957/issue1957.gen.go | 27 +++++++++ .../test/issues/issue1957/issue1957_test.go | 58 +++++++++++++++++++ internal/test/issues/issue1957/openapi.yaml | 55 ++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 internal/test/issues/issue1957/config.yaml create mode 100644 internal/test/issues/issue1957/generate.go create mode 100644 internal/test/issues/issue1957/issue1957.gen.go create mode 100644 internal/test/issues/issue1957/issue1957_test.go create mode 100644 internal/test/issues/issue1957/openapi.yaml diff --git a/internal/test/go.mod b/internal/test/go.mod index f8cc46e28a..3e92667710 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -9,6 +9,7 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi/v5 v5.0.10 github.com/gofiber/fiber/v2 v2.49.1 + github.com/google/uuid v1.4.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 @@ -47,7 +48,6 @@ require ( 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/iris-contrib/schema v0.0.6 // indirect 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..861a76b0e8 --- /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..6d115f179a --- /dev/null +++ b/internal/test/issues/issue1957/issue1957_test.go @@ -0,0 +1,58 @@ +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) { + // TODO that this is NOT wanted behaviour, but it is our current behaviour + t.Run("An optional field with x-go-type-skip-optional-pointer should be a pointer", func(t *testing.T) { + + u := uuid.New() + + theType := GetRootParams{ + At: &u, + } + + require.NotNil(t, theType.At) + require.NotZero(t, *theType.At) + }) + }) + + t.Run("For a field with an AllOf", func(t *testing.T) { + // TODO that this is NOT wanted behaviour, but it is our current behaviour + t.Run("An optional field with x-go-type-skip-optional-pointer should be a pointer", func(t *testing.T) { + + u := uuid.New() + + theType := TypeWithAllOf{ + Id: &u, + } + + require.NotNil(t, theType.Id) + 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 From cc72767e6eaccf2d9ade2fc13cab47e3c006a131 Mon Sep 17 00:00:00 2001 From: Melvin Laplanche Date: Mon, 21 Apr 2025 22:37:43 -0700 Subject: [PATCH 071/293] fix(codegen): allow using x-go-type and x-go-type-skip-optional-pointer together When using `x-go-type`, `GenerateGoSchema` returns early, meaning that any extensions that are checked after this one are no-op. This PR moves the code for `x-go-type-skip-optional-pointer` higher up, so it can be used alongside `x-go-type`. This corrects this piece of behaviour, and amends our generated code examples to correctly apply `x-go-type-skip-optional-pointer` when using an optional field, or inside an `AllOf`. --- .../test/issues/issue1957/issue1957.gen.go | 4 ++-- .../test/issues/issue1957/issue1957_test.go | 16 ++++++--------- pkg/codegen/schema.go | 20 +++++++++---------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/internal/test/issues/issue1957/issue1957.gen.go b/internal/test/issues/issue1957/issue1957.gen.go index 861a76b0e8..ee2c7adb75 100644 --- a/internal/test/issues/issue1957/issue1957.gen.go +++ b/internal/test/issues/issue1957/issue1957.gen.go @@ -12,7 +12,7 @@ type ID = googleuuid.UUID // TypeWithAllOf defines model for TypeWithAllOf. type TypeWithAllOf struct { - Id *googleuuid.UUID `json:"id,omitempty"` + Id googleuuid.UUID `json:"id,omitempty"` } // TypeWithOptionalField defines model for TypeWithOptionalField. @@ -23,5 +23,5 @@ type TypeWithOptionalField struct { // GetRootParams defines parameters for GetRoot. type GetRootParams struct { - At *googleuuid.UUID `form:"at,omitempty" json:"at,omitempty"` + 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 index 6d115f179a..de99ccca36 100644 --- a/internal/test/issues/issue1957/issue1957_test.go +++ b/internal/test/issues/issue1957/issue1957_test.go @@ -27,32 +27,28 @@ func TestGeneratedCode(t *testing.T) { }) t.Run("For a query parameter", func(t *testing.T) { - // TODO that this is NOT wanted behaviour, but it is our current behaviour - t.Run("An optional field with x-go-type-skip-optional-pointer should be a pointer", 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, + At: u, } - require.NotNil(t, theType.At) - require.NotZero(t, *theType.At) + require.NotZero(t, theType.At) }) }) t.Run("For a field with an AllOf", func(t *testing.T) { - // TODO that this is NOT wanted behaviour, but it is our current behaviour - t.Run("An optional field with x-go-type-skip-optional-pointer should be a pointer", 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, + Id: u, } - require.NotNil(t, theType.Id) - require.NotZero(t, *theType.Id) + require.NotZero(t, theType.Id) }) }) } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index f0054a8671..af6781fad6 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -289,6 +289,16 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return mergedSchema, 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) + if err != nil { + return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoTypeSkipOptionalPointer, err) + } + outSchema.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 { @@ -302,16 +312,6 @@ 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) - if err != nil { - return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoTypeSkipOptionalPointer, err) - } - outSchema.SkipOptionalPointer = skipOptionalPointer - } - // Schema type and format, eg. string / binary t := schema.Type // Handle objects and empty schemas first as a special case From b23cf3ea9697fe922a352cfe91795fc1e2c2f592 Mon Sep 17 00:00:00 2001 From: Nolan Di Mare Sullivan Date: Thu, 8 May 2025 01:17:30 -0700 Subject: [PATCH 072/293] docs(sponsors): update Speakeasy URL (#1970) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42ac2f336b..32802242a1 100644 --- a/README.md +++ b/README.md @@ -4211,7 +4211,7 @@ In addition, we are also generously sponsored by the following folks, each of wh

- + From 4d4ade24a97f93ec3eb9fbd458629a0440cdd2c1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 5 May 2025 15:29:23 +0100 Subject: [PATCH 073/293] docs(std-http-server): warn when not using Go 1.22 Although this is less necessary after bumping our minimum Go version to 1.22 (in 0e8156a14e1a92e59194230873b2053d5b29e38b), it's still worthwhile ensuring that the module we're generating the code for is correctly set to Go 1.22, otherwise users will receive: HTTP/1.1 404 Not Found ... 404 page not found To do this, we can introduce a new means to flag "warnings" that need to be output. We need to make sure we're using `ParseLax` to reduce the risk of new directives or content being introduced into a `go.mod` breaking `oapi-codegen`. This is a step towards being able to implement future warnings to ensure that consumers are using correct Go versions. Closes #1628. [0]: https://www.jvt.me/posts/2024/03/04/go-net-http-why-404/ --- cmd/oapi-codegen/oapi-codegen.go | 9 +++ go.mod | 2 +- pkg/codegen/configuration.go | 29 ++++++++++ pkg/codegen/minimum_go_version.go | 91 +++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 pkg/codegen/minimum_go_version.go diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 7098f4d740..cb9e6d906d 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -271,6 +271,15 @@ func main() { errExit("configuration error: %v\n", err) } + if warnings := opts.Generate.Warnings(); len(warnings) > 0 { + out := "WARNING: A number of warning(s) were returned when validating the GenerateOptions:" + for k, v := range warnings { + out += "\n- " + k + ": " + v + } + + _, _ = fmt.Fprint(os.Stderr, out) + } + // If the user asked to output configuration, output it to stdout and exit if flagOutputConfig { buf, err := yaml.Marshal(opts) diff --git a/go.mod b/go.mod index c962eb2d68..e36eaef677 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/getkin/kin-openapi v0.128.0 github.com/speakeasy-api/openapi-overlay v0.10.1 github.com/stretchr/testify v1.10.0 + golang.org/x/mod v0.17.0 golang.org/x/text v0.20.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d gopkg.in/yaml.v2 v2.4.0 @@ -26,5 +27,4 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect ) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 644ead359f..c30e1b5f04 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -132,6 +132,35 @@ 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 { 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 +} From 70fd7679da285f1540a6395cb2c5e1f1c781b311 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 10:47:56 +0000 Subject: [PATCH 074/293] chore(deps): update actions/setup-go digest to d35c59a --- .github/workflows/ci.yml | 2 +- .github/workflows/generate.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tidy.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 384384f6b6..37560a65ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index b35720292f..831d4c5888 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c7748f399e..423340111f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index f01e12f961..a09d6bf35f 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set up Go - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version: ${{ matrix.version }} From a907de0c12a175c062fe34fb27e7cdafac5f72bf Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:35:43 +0100 Subject: [PATCH 075/293] style(errcheck): ignore error from deferred `resp.Body.Close` --- pkg/codegen/codegen.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index ef175afdd5..facddb914d 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -964,7 +964,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) From ef31bd408f923b95982d98e1b47f779c95e8f1c3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:36:28 +0100 Subject: [PATCH 076/293] style(staticcheck): remove remove embedded field from selector --- cmd/oapi-codegen/oapi-codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index cb9e6d906d..c41f3718d3 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -310,7 +310,7 @@ func main() { } if len(noVCSVersionOverride) > 0 { - opts.Configuration.NoVCSVersionOverride = &noVCSVersionOverride + opts.NoVCSVersionOverride = &noVCSVersionOverride } code, err := codegen.Generate(swagger, opts.Configuration) From 3f63dd94ea54486bf3a0b246ac47f13e68b07a6a Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:37:26 +0100 Subject: [PATCH 077/293] style(staticcheck): error strings should not be capitalized --- .../authenticated-api/echo/server/jwt_authenticator.go | 6 +++--- .../stdhttp/server/jwt_authenticator.go | 6 +++--- pkg/codegen/operations.go | 2 +- pkg/ecdsafile/ecdsafile.go | 4 ++-- pkg/util/loader.go | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/authenticated-api/echo/server/jwt_authenticator.go b/examples/authenticated-api/echo/server/jwt_authenticator.go index 2638a0f5f2..c9d9a73a5a 100644 --- a/examples/authenticated-api/echo/server/jwt_authenticator.go +++ b/examples/authenticated-api/echo/server/jwt_authenticator.go @@ -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 diff --git a/examples/authenticated-api/stdhttp/server/jwt_authenticator.go b/examples/authenticated-api/stdhttp/server/jwt_authenticator.go index 0cecccf04d..b29a67302c 100644 --- a/examples/authenticated-api/stdhttp/server/jwt_authenticator.go +++ b/examples/authenticated-api/stdhttp/server/jwt_authenticator.go @@ -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 diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index dd6b913b3d..195f8a0c53 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -300,7 +300,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini if contentType.Schema != nil { responseSchema, err := GenerateGoSchema(contentType.Schema, []string{o.OperationId, responseName}) if err != nil { - return nil, fmt.Errorf("Unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) + return nil, fmt.Errorf("unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) } var typeName string 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 8c56cf211a..89830a8c44 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -66,24 +66,24 @@ func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (s err = overlay.Validate() if err != nil { - return nil, fmt.Errorf("The Overlay in %#v was not valid: %v", opts.Path, err) + return nil, fmt.Errorf("the Overlay in %#v was not valid: %v", opts.Path, err) } if opts.Strict { err, vs := 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- ")) + 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) + 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) + return nil, fmt.Errorf("failed to serialize Overlay'd specification %#v: %v", opts.Path, err) } loader := openapi3.NewLoader() @@ -93,7 +93,7 @@ func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (s Path: filepath.ToSlash(filePath), }) if err != nil { - return nil, fmt.Errorf("Failed to serialize Overlay'd specification %#v: %v", opts.Path, err) + return nil, fmt.Errorf("failed to serialize Overlay'd specification %#v: %v", opts.Path, err) } return swagger, nil From 1cf0c54d4b20bc0381a4b5156a2efd9b6c1fd3e6 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:38:11 +0100 Subject: [PATCH 078/293] style(staticcheck): remove Yoda conditional, must we --- pkg/codegen/operations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 195f8a0c53..7792400951 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -309,7 +309,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini // HAL+JSON: case StringInArray(contentTypeName, contentTypesHalJSON): typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName)) - case "application/json" == contentTypeName: + case contentTypeName == "application/json": // if it's the standard application/json typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName)) // Vendored JSON From 4a04a85cdcc48d5a646d2a38470b1ccbcd619e89 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:41:13 +0100 Subject: [PATCH 079/293] style(staticcheck): migrate nolint from `gosimple` --- pkg/codegen/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 962b967505..6ecf27433c 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -1099,7 +1099,7 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool { return false } - return *s.AdditionalProperties.Has == false //nolint:gosimple + return *s.AdditionalProperties.Has == false //nolint:staticcheck } func sliceContains[E comparable](s []E, v E) bool { From 7b4762a912d1b5989080579daa0838e2ac9585e1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:42:52 +0100 Subject: [PATCH 080/293] style(staticcheck): use tagged switches --- pkg/codegen/schema.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index af6781fad6..2151681fc2 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -583,37 +583,39 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem } else if t.Is("integer") { // We default to int if format doesn't ask for something else. - if f == "int64" { + switch f { + case "int64": outSchema.GoType = "int64" - } else if f == "int32" { + case "int32": outSchema.GoType = "int32" - } else if f == "int16" { + case "int16": outSchema.GoType = "int16" - } else if f == "int8" { + case "int8": outSchema.GoType = "int8" - } else if f == "int" { + case "int": outSchema.GoType = "int" - } else if f == "uint64" { + case "uint64": outSchema.GoType = "uint64" - } else if f == "uint32" { + case "uint32": outSchema.GoType = "uint32" - } else if f == "uint16" { + case "uint16": outSchema.GoType = "uint16" - } else if f == "uint8" { + case "uint8": outSchema.GoType = "uint8" - } else if f == "uint" { + case "uint": outSchema.GoType = "uint" - } else { + default: outSchema.GoType = "int" } outSchema.DefineViaAlias = true } else if t.Is("number") { // We default to float for "number" - if f == "double" { + switch f { + case "double": outSchema.GoType = "float64" - } else if f == "float" || f == "" { + case "float", "": outSchema.GoType = "float32" - } else { + default: return fmt.Errorf("invalid number format: %s", f) } outSchema.DefineViaAlias = true From 579b542184737ca0c97109d442d1fdc44c5ad164 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 9 May 2025 08:44:49 +0100 Subject: [PATCH 081/293] style: refactor duplicated tagged switch As there's no point it should be so heavily duplicated. --- pkg/codegen/schema.go | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 2151681fc2..c106538bad 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -584,26 +584,17 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem } else if t.Is("integer") { // We default to int if format doesn't ask for something else. switch f { - case "int64": - outSchema.GoType = "int64" - case "int32": - outSchema.GoType = "int32" - case "int16": - outSchema.GoType = "int16" - case "int8": - outSchema.GoType = "int8" - case "int": - outSchema.GoType = "int" - case "uint64": - outSchema.GoType = "uint64" - case "uint32": - outSchema.GoType = "uint32" - case "uint16": - outSchema.GoType = "uint16" - case "uint8": - outSchema.GoType = "uint8" - case "uint": - outSchema.GoType = "uint" + case "int64", + "int32", + "int16", + "int8", + "int", + "uint64", + "uint32", + "uint16", + "uint8", + "uint": + outSchema.GoType = f default: outSchema.GoType = "int" } From 48e28f4de8ce17188c1f191efa898fef014f4baf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 May 2025 18:25:53 +0000 Subject: [PATCH 082/293] chore(deps): update module github.com/golangci/golangci-lint to v2 --- Makefile | 4 ++-- examples/Makefile | 2 +- examples/authenticated-api/stdhttp/Makefile | 2 +- examples/minimal-server/stdhttp-go-tool/Makefile | 2 +- examples/minimal-server/stdhttp/Makefile | 2 +- examples/petstore-expanded/stdhttp/Makefile | 2 +- internal/test/Makefile | 2 +- internal/test/strict-server/stdhttp/Makefile | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index aca6de83eb..8c63b973f9 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.64.5 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v2.1.6 .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/examples/Makefile b/examples/Makefile index 93a6cdb16f..5ec0edd058 100644 --- a/examples/Makefile +++ b/examples/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/examples/authenticated-api/stdhttp/Makefile b/examples/authenticated-api/stdhttp/Makefile index dac22331f7..7173d70211 100644 --- a/examples/authenticated-api/stdhttp/Makefile +++ b/examples/authenticated-api/stdhttp/Makefile @@ -21,7 +21,7 @@ lint: lint-ci: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: $(call execute-if-go-122,go generate ./...) diff --git a/examples/minimal-server/stdhttp-go-tool/Makefile b/examples/minimal-server/stdhttp-go-tool/Makefile index a25a6994c9..e99db23781 100644 --- a/examples/minimal-server/stdhttp-go-tool/Makefile +++ b/examples/minimal-server/stdhttp-go-tool/Makefile @@ -21,7 +21,7 @@ lint: lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m) + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: $(call execute-if-go-124,go generate ./...) diff --git a/examples/minimal-server/stdhttp/Makefile b/examples/minimal-server/stdhttp/Makefile index 66f60e4a23..7173d70211 100644 --- a/examples/minimal-server/stdhttp/Makefile +++ b/examples/minimal-server/stdhttp/Makefile @@ -21,7 +21,7 @@ lint: lint-ci: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: $(call execute-if-go-122,go generate ./...) diff --git a/examples/petstore-expanded/stdhttp/Makefile b/examples/petstore-expanded/stdhttp/Makefile index 66f60e4a23..7173d70211 100644 --- a/examples/petstore-expanded/stdhttp/Makefile +++ b/examples/petstore-expanded/stdhttp/Makefile @@ -21,7 +21,7 @@ lint: lint-ci: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: $(call execute-if-go-122,go generate ./...) 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/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile index dac22331f7..7173d70211 100644 --- a/internal/test/strict-server/stdhttp/Makefile +++ b/internal/test/strict-server/stdhttp/Makefile @@ -21,7 +21,7 @@ lint: lint-ci: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: $(call execute-if-go-122,go generate ./...) From bd4c2df10f9bbf3514f373f36184c3c99bb86e2a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 May 2025 18:08:58 +0000 Subject: [PATCH 083/293] fix(deps): update module github.com/speakeasy-api/openapi-overlay to v0.10.2 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 4 ++-- examples/go.mod | 2 +- examples/go.sum | 4 ++-- examples/minimal-server/stdhttp-go-tool/go.mod | 2 +- examples/minimal-server/stdhttp-go-tool/go.sum | 4 ++-- examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index e808d10f40..935aecbefe 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -34,7 +34,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.17.0 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index f436fbe0bc..b9df64e432 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -101,8 +101,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/go.mod b/examples/go.mod index 0b4da16308..eb2bfe37e5 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -92,7 +92,7 @@ require ( github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/tdewolff/minify/v2 v2.12.9 // indirect github.com/tdewolff/parse/v2 v2.6.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index bdc31d6292..e783fc97e3 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -250,8 +250,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 7334634331..e122ee9d19 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -18,7 +18,7 @@ require ( github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index 39478df520..e8c27f0da0 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -75,8 +75,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index f0e5063363..6bf90d508f 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -17,7 +17,7 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 39478df520..e8c27f0da0 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -75,8 +75,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index cd7e03907c..4e430e7599 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -28,7 +28,7 @@ require ( github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index aaebd5a0dd..3cee4a7c00 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -90,8 +90,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/go.mod b/go.mod index e36eaef677..12fdc6a787 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22 require ( github.com/getkin/kin-openapi v0.128.0 - github.com/speakeasy-api/openapi-overlay v0.10.1 + github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.10.0 golang.org/x/mod v0.17.0 golang.org/x/text v0.20.0 diff --git a/go.sum b/go.sum index 39478df520..e8c27f0da0 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 3e92667710..2ee32358df 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -79,7 +79,7 @@ require ( github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // 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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 752fd496c8..e551d7c7a4 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -228,8 +228,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 5813694fbb..1b32924c17 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -29,7 +29,7 @@ require ( github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 0a34b1cbdf..970b345a42 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -86,8 +86,8 @@ 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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.1 h1:XFx/GvJvtAGf4dcQ6bxzsLNf76x/QWE2X0SSZrWojBQ= -github.com/speakeasy-api/openapi-overlay v0.10.1/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= 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= From 0a61b433b0d90811959c5d533d555d40a978347c Mon Sep 17 00:00:00 2001 From: jens1205 <76230007+jens1205@users.noreply.github.com> Date: Sat, 10 May 2025 19:40:45 +0200 Subject: [PATCH 084/293] fix: don't generate an "optional pointer" for unknown types (#610) As noted in #609, this doesn't make sense, and makes it harder to interact with. Closes #609. Co-authored-by: Jens Gersdorf Co-authored-by: Jamie Tanna --- internal/test/issues/issue609/config.yaml | 7 +++++++ internal/test/issues/issue609/generate.go | 3 +++ internal/test/issues/issue609/issue609.gen.go | 9 +++++++++ internal/test/issues/issue609/openapi.yaml | 11 +++++++++++ pkg/codegen/schema.go | 2 ++ 5 files changed, 32 insertions(+) create mode 100644 internal/test/issues/issue609/config.yaml create mode 100644 internal/test/issues/issue609/generate.go create mode 100644 internal/test/issues/issue609/issue609.gen.go create mode 100644 internal/test/issues/issue609/openapi.yaml 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/pkg/codegen/schema.go b/pkg/codegen/schema.go index c106538bad..9ca303d91b 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -329,6 +329,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // 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 From ccfe27a7d123278872bde02c04db9c70994e54ac Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sat, 10 May 2025 19:55:36 +0200 Subject: [PATCH 085/293] feat(output-options): add `prefer-skip-optional-pointer` to default to skipping optional pointers 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. It's possible for users to override this using behaviour on a per-type or per-field basis using the `x-go-type-skip-optional-pointer` extension, but as has been flagged before (#1454, #1860), this can be very cumbersome. It's possible to use an OpenAPI Overlay to simplify this - but comes at the cost of likely using a complex JSON Path - so we should provide a more reasonable option to default this behaviour, with an Output Option. This will be an opt-in default, but with the ability to override the behaviour on a per-type/per-field basis, allowing control of when we should be able to use them. This also introduces a test to validate this behaviour. Co-authored-by: Jamie Tanna --- README.md | 5 +++ configuration-schema.json | 5 +++ .../preferskipoptionalpointer/api.yaml | 33 +++++++++++++++++++ .../preferskipoptionalpointer/cfg.yaml | 9 +++++ .../preferskipoptionalpointer/gen.go | 25 ++++++++++++++ .../preferskipoptionalpointer/generate.go | 3 ++ pkg/codegen/configuration.go | 4 +++ pkg/codegen/schema.go | 2 ++ pkg/codegen/templates/chi/chi-middleware.tmpl | 8 ++--- pkg/codegen/templates/echo/echo-wrappers.tmpl | 6 ++-- .../templates/fiber/fiber-middleware.tmpl | 14 ++++---- pkg/codegen/templates/gin/gin-wrappers.tmpl | 14 ++++---- .../templates/gorilla/gorilla-middleware.tmpl | 14 ++++---- .../templates/iris/iris-middleware.tmpl | 14 ++++---- 14 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 examples/output-options/preferskipoptionalpointer/api.yaml create mode 100644 examples/output-options/preferskipoptionalpointer/cfg.yaml create mode 100644 examples/output-options/preferskipoptionalpointer/gen.go create mode 100644 examples/output-options/preferskipoptionalpointer/generate.go diff --git a/README.md b/README.md index 32802242a1..189283ca9c 100644 --- a/README.md +++ b/README.md @@ -2287,6 +2287,11 @@ Do not add a pointer type for optional fields in structs

+> [!TIP] +> If you prefer this behaviour, and prefer to not have to annotate your whole OpenAPI spec for this behaviour, you can use `output-options.prefer-skip-optional-pointer=true` to default this behaviour for all fields. +> +> It is then possible to override this on a per-type/per-field basis where necessary. + By default, `oapi-codegen` will generate a pointer for optional fields. Using the `x-go-type-skip-optional-pointer` extension allows omitting that pointer. diff --git a/configuration-schema.json b/configuration-schema.json index 53cfc64b95..1cf2d8599c 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -233,6 +233,11 @@ "client-response-bytes-function": { "type": "boolean", "description": "Enable the generation of a `Bytes()` method on response objects for `ClientWithResponses`" + }, + "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 } } }, diff --git a/examples/output-options/preferskipoptionalpointer/api.yaml b/examples/output-options/preferskipoptionalpointer/api.yaml new file mode 100644 index 0000000000..3ba1bfdd1b --- /dev/null +++ b/examples/output-options/preferskipoptionalpointer/api.yaml @@ -0,0 +1,33 @@ +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 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..01749ecddc --- /dev/null +++ b/examples/output-options/preferskipoptionalpointer/gen.go @@ -0,0 +1,25 @@ +// 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"` +} 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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index c30e1b5f04..bcafb476fa 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -285,6 +285,10 @@ type OutputOptions struct { // ClientResponseBytesFunction decides whether to enable the generation of a `Bytes()` method on response objects for `ClientWithResponses` ClientResponseBytesFunction bool `yaml:"client-response-bytes-function,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"` } func (oo OutputOptions) Validate() map[string]string { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 9ca303d91b..dbe22f8055 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -274,6 +274,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { outSchema := Schema{ Description: schema.Description, OAPISchema: schema, + // NOTE that SkipOptionalPointer will be defaulted to the global value, but can be overridden on a per-type/-field basis + SkipOptionalPointer: globalState.options.OutputOptions.PreferSkipOptionalPointer, } // AllOf is interesting, and useful. It's the union of a number of other diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index 9423a67f2c..fe17246dbb 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index 1603c3d5c8..b642245d36 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -84,7 +84,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { 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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 0904c7894d..36881125c3 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -59,7 +59,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found") @@ -93,7 +93,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { var {{.GoName}} {{.TypeDef}} {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{if .IsJson}} @@ -110,7 +110,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { } {{end}} - params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err) @@ -126,7 +126,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if cookie = c.Cookies("{{.ParamName}}"); cookie == "" { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}cookie + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -142,7 +142,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -151,7 +151,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { 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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 8f1a6b229f..84b54c0914 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -55,7 +55,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -66,7 +66,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest) @@ -96,7 +96,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -115,7 +115,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{end}} - params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found"), http.StatusBadRequest) @@ -132,7 +132,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -150,7 +150,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -160,7 +160,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { 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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index 85b04c89fa..315130799f 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"}) @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -164,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index ae40439ef4..e0276816b6 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -55,7 +55,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{else}} if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -65,7 +65,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) @@ -87,7 +87,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -105,7 +105,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{end}} - params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { ctx.StatusCode(http.StatusBadRequest) ctx.WriteString("Header {{.ParamName}} is required, but not found") @@ -117,7 +117,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{range .CookieParams}} if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil { {{if .IsPassThrough}} - params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -134,7 +134,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{if .IsStyled}} var value {{.TypeDef}} @@ -144,7 +144,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err) return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) From 8ea9351bbd3e4064637c2ab87c3665ee376569ac Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 10 May 2025 18:42:32 +0100 Subject: [PATCH 086/293] feat(output-options): add `prefer-skip-optional-pointer-on-container-types` 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. It's possible for users to override this using behaviour on a per-type or per-field basis using the `x-go-type-skip-optional-pointer` extension, but there are cases, as noted in #1561, where we're generating the optional pointer for container types (such as slices or maps) which doesn't make sense, as it requires an extra level of `... != nil` checks. Therefore we should introduce a new opt-in Output Option to allow skipping the optional pointer on a container type. Closes #1561. --- configuration-schema.json | 5 ++ internal/test/issues/issue1561/config.yaml | 8 +++ internal/test/issues/issue1561/generate.go | 3 + .../test/issues/issue1561/issue1561.gen.go | 21 ++++++ .../test/issues/issue1561/issue1561_test.go | 64 +++++++++++++++++++ internal/test/issues/issue1561/openapi.yaml | 49 ++++++++++++++ pkg/codegen/configuration.go | 3 + pkg/codegen/schema.go | 15 +++++ 8 files changed, 168 insertions(+) create mode 100644 internal/test/issues/issue1561/config.yaml create mode 100644 internal/test/issues/issue1561/generate.go create mode 100644 internal/test/issues/issue1561/issue1561.gen.go create mode 100644 internal/test/issues/issue1561/issue1561_test.go create mode 100644 internal/test/issues/issue1561/openapi.yaml diff --git a/configuration-schema.json b/configuration-schema.json index 1cf2d8599c..fefbc19c86 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -238,6 +238,11 @@ "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-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 } } }, 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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index bcafb476fa..5608e227cd 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -289,6 +289,9 @@ type OutputOptions struct { // 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"` + + // 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"` } func (oo OutputOptions) Validate() map[string]string { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index dbe22f8055..7d061bc7d8 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -327,6 +327,7 @@ 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. @@ -389,6 +390,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 } @@ -584,6 +586,7 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem if sliceContains(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. @@ -625,6 +628,7 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem switch f { case "byte": outSchema.GoType = "[]byte" + setSkipOptionalPointerForContainerType(outSchema) case "email": outSchema.GoType = "openapi_types.Email" case "date": @@ -892,3 +896,14 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato 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 +} From 821dce9fe8afbdba642de59097762cbb77db41f3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 11 May 2025 11:19:14 +0100 Subject: [PATCH 087/293] chore(tests): add additional test case for underscore naming As highlighted in #1767. --- internal/test/issues/issue1767/config.yaml | 7 +++++++ internal/test/issues/issue1767/generate.go | 3 +++ .../test/issues/issue1767/issue1767.gen.go | 17 ++++++++++++++++ internal/test/issues/issue1767/openapi.yaml | 20 +++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 internal/test/issues/issue1767/config.yaml create mode 100644 internal/test/issues/issue1767/generate.go create mode 100644 internal/test/issues/issue1767/issue1767.gen.go create mode 100644 internal/test/issues/issue1767/openapi.yaml 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 From 453f222046ff447561da910c4254ba5fc2796ec3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 11 May 2025 16:09:22 +0100 Subject: [PATCH 088/293] feat(templates): add `HasOptionalPointer` helper As a means to consolidate our logic for whether a type has an optional pointer in templates, we can introduce a new helper method, `HasOptionalPointer`, which will indicate whether a given type - in a template - should have an "optional pointer" to indicate whether the field is optional. This wires it in for both properties (of structs) or parameter definitions. To start with, we will derive this based on whether it is required, and will add support for the `x-go-type-skip-optional-pointer` extension afterwards. --- pkg/codegen/operations.go | 6 ++++ pkg/codegen/schema.go | 6 ++++ .../templates/additional-properties.tmpl | 6 ++-- pkg/codegen/templates/chi/chi-middleware.tmpl | 14 ++++----- pkg/codegen/templates/client.tmpl | 30 +++++++++---------- pkg/codegen/templates/echo/echo-wrappers.tmpl | 14 ++++----- .../templates/fiber/fiber-middleware.tmpl | 14 ++++----- pkg/codegen/templates/gin/gin-wrappers.tmpl | 14 ++++----- .../templates/gorilla/gorilla-middleware.tmpl | 14 ++++----- .../templates/iris/iris-middleware.tmpl | 14 ++++----- .../stdhttp/std-http-middleware.tmpl | 14 ++++----- .../union-and-additional-properties.tmpl | 4 +-- pkg/codegen/templates/union.tmpl | 4 +-- 13 files changed, 83 insertions(+), 71 deletions(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 7792400951..e8ea1084cb 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -139,6 +139,12 @@ func (pd ParameterDefinition) IndirectOptional() bool { return !pd.Required && !pd.Schema.SkipOptionalPointer } +// HasOptionalPointer indicates whether the generated property has an optional pointer associated with it. +// NOTE that this does not take into account the `x-go-type-skip-optional-pointer` extension +func (pd ParameterDefinition) HasOptionalPointer() bool { + return pd.Required == false //nolint:staticcheck +} + type ParameterDefinitions []ParameterDefinition func (p ParameterDefinitions) FindByName(name string) *ParameterDefinition { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 7d061bc7d8..1e104ff3fe 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -128,6 +128,12 @@ func (p Property) GoTypeDef() string { return typeDef } +// HasOptionalPointer indicates whether the generated property has an optional pointer associated with it. +// NOTE that this does not take into account the `x-go-type-skip-optional-pointer` extension +func (p Property) HasOptionalPointer() bool { + return p.Required == false //nolint:staticcheck +} + // 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 diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl index 7b7c0ace4b..2f450582d1 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 .HasOptionalPointer}}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 .HasOptionalPointer}} }{{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-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index fe17246dbb..0d66bd274b 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ 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 +69,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}}"}) @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -164,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 10ee5644d2..822e11097a 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -197,12 +197,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr if params != nil { queryValues := queryURL.Query() {{range $paramIdx, $param := .QueryParams}} - {{if not .Required}} if params.{{.GoName}} != nil { {{end}} + {{if .HasOptionalPointer}} 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,7 +210,7 @@ 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.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -222,7 +222,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr } } {{end}} - {{if not .Required}}}{{end}} + {{if .HasOptionalPointer}}}{{end}} {{end}} queryURL.RawQuery = queryValues.Encode() } @@ -236,27 +236,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 .HasOptionalPointer}} 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.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } {{end}} req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}}) - {{if not .Required}}}{{end}} + {{if .HasOptionalPointer}}}{{end}} {{end}} } {{- end }}{{/* if .HeaderParams */}} @@ -264,21 +264,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 .HasOptionalPointer}} 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.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}) if err != nil { return nil, err } @@ -288,7 +288,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr Value:cookieParam{{$paramIdx}}, } req.AddCookie(cookie{{$paramIdx}}) - {{if not .Required}}}{{end}} + {{if .HasOptionalPointer}}}{{end}} {{ end -}} } {{- end }}{{/* if .CookieParams */}} diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index b642245d36..010b42ceb6 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -44,7 +44,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { {{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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -84,7 +84,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -107,7 +107,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 .IsStyled}} var value {{.TypeDef}} @@ -115,7 +115,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { 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")) diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 36881125c3..d780924ab7 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -59,7 +59,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found") @@ -93,7 +93,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { var {{.GoName}} {{.TypeDef}} {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{if .IsJson}} @@ -110,7 +110,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err) @@ -126,7 +126,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if cookie = c.Cookies("{{.ParamName}}"); cookie == "" { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}}&{{end}}cookie + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -142,7 +142,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 and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -151,7 +151,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 84b54c0914..3a76b48b1b 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -55,7 +55,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -66,7 +66,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest) @@ -96,7 +96,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -115,7 +115,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found"), http.StatusBadRequest) @@ -132,7 +132,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { if cookie, err = c.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -150,7 +150,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -160,7 +160,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest) return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index 315130799f..b388c2703d 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"}) @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -164,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index e0276816b6..6f7b493ecb 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -55,7 +55,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{else}} if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -65,7 +65,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON") return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) @@ -87,7 +87,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -105,7 +105,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{end}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} } {{if .Required}}else { ctx.StatusCode(http.StatusBadRequest) ctx.WriteString("Header {{.ParamName}} is required, but not found") @@ -117,7 +117,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{range .CookieParams}} if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -134,7 +134,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON") return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} {{if .IsStyled}} var value {{.TypeDef}} @@ -144,7 +144,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err) return } - params.{{.GoName}} = {{if and (not .Required) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) diff --git a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl index 19f1fe2950..09977358c8 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ 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 +69,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}}"}) @@ -98,7 +98,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}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{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") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ 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}} @@ -154,7 +154,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 .IsStyled}} @@ -164,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return } - params.{{.GoName}} = {{if not .Required}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl index 79b4c67b2e..1c48092ccf 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 .HasOptionalPointer}}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 .HasOptionalPointer}} }{{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..c0385f82e3 100644 --- a/pkg/codegen/templates/union.tmpl +++ b/pkg/codegen/templates/union.tmpl @@ -102,12 +102,12 @@ } } {{range .Schema.Properties}} - {{if not .Required}}if t.{{.GoFieldName}} != nil { {{end}} + {{if .HasOptionalPointer}}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 .HasOptionalPointer}} }{{end}} {{end -}} b, err = json.Marshal(object) {{end -}} From 9988c5490e0b8d5f63562ae00ebe1da45630528f Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 11 May 2025 16:39:30 +0100 Subject: [PATCH 089/293] feat(templates): include `x-go-type-skip-optional-pointer` in `HasOptionalPointer` As a follow-up to introducing `HasOptionalPointer`, we can then reduce duplication around checking for the `x-go-type-skip-optional-pointer`, to allow more general control over the generation. This doesn't impact any of our existing generated code, as it doesn't utilise `x-go-type-skip-optional-pointer`. --- pkg/codegen/operations.go | 4 ++-- pkg/codegen/schema.go | 4 ++-- pkg/codegen/templates/chi/chi-middleware.tmpl | 8 ++++---- pkg/codegen/templates/echo/echo-wrappers.tmpl | 6 +++--- pkg/codegen/templates/fiber/fiber-middleware.tmpl | 14 +++++++------- pkg/codegen/templates/gin/gin-wrappers.tmpl | 14 +++++++------- .../templates/gorilla/gorilla-middleware.tmpl | 14 +++++++------- pkg/codegen/templates/iris/iris-middleware.tmpl | 14 +++++++------- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index e8ea1084cb..ad9e52b2c9 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -140,9 +140,9 @@ func (pd ParameterDefinition) IndirectOptional() bool { } // HasOptionalPointer indicates whether the generated property has an optional pointer associated with it. -// NOTE that this does not take into account the `x-go-type-skip-optional-pointer` extension +// 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 == false //nolint:staticcheck + return pd.Required == false && pd.Schema.SkipOptionalPointer == false //nolint:staticcheck } type ParameterDefinitions []ParameterDefinition diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 1e104ff3fe..d2e64f9805 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -129,9 +129,9 @@ func (p Property) GoTypeDef() string { } // HasOptionalPointer indicates whether the generated property has an optional pointer associated with it. -// NOTE that this does not take into account the `x-go-type-skip-optional-pointer` extension +// 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 == false //nolint:staticcheck + return p.Required == false && p.Schema.SkipOptionalPointer == false //nolint:staticcheck } // EnumDefinition holds type information for enum diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index 0d66bd274b..97866fca6a 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if .HasOptionalPointer }}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}} } {{if .Required}}else { err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{- if .IsStyled}} diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index 010b42ceb6..ea7b75eaad 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -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 and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -84,7 +84,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{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 and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index d780924ab7..e44f4836cb 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -59,7 +59,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,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 and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} }{{if .Required}} else { err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found") @@ -93,7 +93,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { var {{.GoName}} {{.TypeDef}} {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{if .IsJson}} @@ -110,7 +110,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err) @@ -126,7 +126,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if cookie = c.Cookies("{{.ParamName}}"); cookie == "" { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}}&{{end}}cookie + params.{{.GoName}} = {{if .HasOptionalPointer}}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -142,7 +142,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 and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -151,7 +151,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 3a76b48b1b..3bc02e5d7f 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -55,7 +55,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { if paramValue := c.Query("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -66,7 +66,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{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) @@ -96,7 +96,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -115,7 +115,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{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 +132,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { if cookie, err = c.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie {{end}} {{- if .IsJson}} @@ -150,7 +150,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -160,7 +160,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest) return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index b388c2703d..e8aa9799f0 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue {{end}} {{if .IsJson}} @@ -69,7 +69,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} }{{if .Required}} else { siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"}) @@ -98,7 +98,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0] {{end}} {{if .IsJson}} @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}} } {{if .Required}}else { err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found") @@ -135,7 +135,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil { {{- if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value {{end}} {{- if .IsJson}} @@ -154,7 +154,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{- if .IsStyled}} @@ -164,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} } diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index 6f7b493ecb..814e6bc4e4 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -55,7 +55,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{else}} if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}paramValue + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -65,7 +65,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON") return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) @@ -87,7 +87,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}valueList[0] + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0] {{end}} {{if .IsJson}} err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}}) @@ -105,7 +105,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{end}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}{{.GoName}} + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}} } {{if .Required}}else { ctx.StatusCode(http.StatusBadRequest) ctx.WriteString("Header {{.ParamName}} is required, but not found") @@ -117,7 +117,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{range .CookieParams}} if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil { {{if .IsPassThrough}} - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}cookie.Value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value {{end}} {{if .IsJson}} var value {{.TypeDef}} @@ -134,7 +134,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON") return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} {{if .IsStyled}} var value {{.TypeDef}} @@ -144,7 +144,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err) return } - params.{{.GoName}} = {{if and (.HasOptionalPointer) (not .Schema.SkipOptionalPointer)}}&{{end}}value + params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value {{end}} }{{if .Required}} else { ctx.StatusCode(http.StatusBadRequest) From c8cf342fd5ea5df5bcf63cd8c16d9fb8177dcd13 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 11 May 2025 16:42:05 +0100 Subject: [PATCH 090/293] chore(codegen): deprecate `IndirectOptional` As it's unclear form the name what it is. --- pkg/codegen/operations.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index ad9e52b2c9..e4d9784702 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -135,6 +135,7 @@ 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 } From da55f7829addff44c1a2e4389421df516a4e0ccf Mon Sep 17 00:00:00 2001 From: Ilia Sevostianov <1166655+i-sevostyanov@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:16:12 +0400 Subject: [PATCH 091/293] docs(extensions): correct typo to example (#1999) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 189283ca9c..977f4425a0 100644 --- a/README.md +++ b/README.md @@ -2787,7 +2787,7 @@ const ( type ClientTypeWithExtension string ``` -You can see this in more detail in [the example code](examples/extensions/xenumvarnames/). +You can see this in more detail in [the example code](examples/extensions/xenumnames/).
From b8ebad4d568a5e53dc883ba5f66a5f4ea1f93908 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 11 Jun 2025 15:23:39 +0100 Subject: [PATCH 092/293] docs(extensions): update example code for `x-enumNames` As the copy in the README was out-of-sync with the generated code. --- README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 977f4425a0..20c6d8fcc7 100644 --- a/README.md +++ b/README.md @@ -2774,17 +2774,26 @@ const ( EXP ClientType = "EXP" ) -// ClientType defines model for ClientType. -type ClientType string +// Defines values for ClientTypeWithNamesExtension. +const ( + ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT" + ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP" +) -// Defines values for ClientTypeWithExtension. +// Defines values for ClientTypeWithVarNamesExtension. const ( - Active ClientTypeWithExtension = "ACT" - Expired ClientTypeWithExtension = "EXP" + ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT" + ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP" ) -// ClientTypeWithExtension defines model for ClientTypeWithExtension. -type ClientTypeWithExtension string +// ClientType defines model for ClientType. +type ClientType string + +// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension. +type ClientTypeWithNamesExtension string + +// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension. +type ClientTypeWithVarNamesExtension string ``` You can see this in more detail in [the example code](examples/extensions/xenumnames/). From aae687ce8fe987714a5c6ba1e18a704dc4503209 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 14 Jun 2025 13:52:18 +0100 Subject: [PATCH 093/293] feat(generate): allow generating Server URL boilerplate When working with a client generated by `oapi-codegen`, it can be a little awkward to manage changing URLs for the `client.WithBaseURL`. Although it's possible to manage these ourselves - with hardcoded values - it can be handy to have this pre-generated, especially if the input spec already defines `$.servers`. This introduces the capability to opt-in to the generation (as we try to make all changes opt-in where possible) of these. This is a little more complicated than ""just"" generating constants, as a Server object could introduce a templated URL. This requires we: - generate the `const`s for non-templated URLs - generate the more in-depth boilerplate for templated URLs We try and do most of the generating in the template, rather than in Go code, although it's not straightforward to generate the method parameters for the generated function (i.e. `NewServerUrlTheProductionAPIServer`) so we create a `genServerURLWithVariablesFunctionParams` function. We'll leave a few cases of additional validation or handling of edge cases to a follow-up. --- README.md | 65 +++++++++++++++++++ configuration-schema.json | 4 ++ examples/generate/serverurls/api.yaml | 47 ++++++++++++++ examples/generate/serverurls/cfg.yaml | 8 +++ examples/generate/serverurls/gen.go | 74 ++++++++++++++++++++++ examples/generate/serverurls/gen_test.go | 48 ++++++++++++++ examples/generate/serverurls/generate.go | 3 + pkg/codegen/codegen.go | 13 ++++ pkg/codegen/configuration.go | 2 + pkg/codegen/server_urls.go | 81 ++++++++++++++++++++++++ pkg/codegen/template_helpers.go | 23 +++++++ pkg/codegen/templates/server-urls.tmpl | 61 ++++++++++++++++++ 12 files changed, 429 insertions(+) create mode 100644 examples/generate/serverurls/api.yaml create mode 100644 examples/generate/serverurls/cfg.yaml create mode 100644 examples/generate/serverurls/gen.go create mode 100644 examples/generate/serverurls/gen_test.go create mode 100644 examples/generate/serverurls/generate.go create mode 100644 pkg/codegen/server_urls.go create mode 100644 pkg/codegen/templates/server-urls.tmpl diff --git a/README.md b/README.md index 20c6d8fcc7..bbeb6df669 100644 --- a/README.md +++ b/README.md @@ -1731,6 +1731,71 @@ 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). + ## 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. diff --git a/configuration-schema.json b/configuration-schema.json index fefbc19c86..0b35d7e657 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -56,6 +56,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" } } }, diff --git a/examples/generate/serverurls/api.yaml b/examples/generate/serverurls/api.yaml new file mode 100644 index 0000000000..48695165ba --- /dev/null +++ b/examples/generate/serverurls/api.yaml @@ -0,0 +1,47 @@ +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 type that's defined, but doesn't have a default + noDefault: {} + # # TODO this conflict will cause broken generated code https://github.com/oapi-codegen/oapi-codegen/issues/2003 + # conflicting: + # enum: + # - 'default' + # - '443' + # default: 'default' +# 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:80 + description: Development server +# make sure that the lowercase `description` gets converted to an uppercase +- url: http://localhost:80 + description: some lowercase name +# there may be URLs on their own, without a `description` +- url: http://localhost:443 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..5f9e069d3e --- /dev/null +++ b/examples/generate/serverurls/gen.go @@ -0,0 +1,74 @@ +// 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" +) + +// 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:80" + +// ServerUrlHttplocalhost443 defines the Server URL for +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:80" + +// 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" + +// ServerUrlTheProductionAPIServerNoDefaultVariable is the `noDefault` variable for ServerUrlTheProductionAPIServer +type ServerUrlTheProductionAPIServerNoDefaultVariable string + +// ServerUrlTheProductionAPIServerPortVariable is the `port` variable for ServerUrlTheProductionAPIServer +type ServerUrlTheProductionAPIServerPortVariable string + +// ServerUrlTheProductionAPIServerPortVariable8443 is one of the accepted values for the `port` variable for ServerUrlTheProductionAPIServer +const ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443" + +// ServerUrlTheProductionAPIServerPortVariable443 is one of the accepted values for the `port` variable for ServerUrlTheProductionAPIServer +const ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443" + +// ServerUrlTheProductionAPIServerPortVariableDefault is the default choice, for the accepted values for the `port` variable for ServerUrlTheProductionAPIServer +const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443 + +// ServerUrlTheProductionAPIServerUsernameVariable is the `username` variable for ServerUrlTheProductionAPIServer +type ServerUrlTheProductionAPIServerUsernameVariable string + +// ServerUrlTheProductionAPIServerUsernameVariableDefault is the default value for the `username` variable for ServerUrlTheProductionAPIServer +const ServerUrlTheProductionAPIServerUsernameVariableDefault = "demo" + +// NewServerUrlTheProductionAPIServer constructs the Server URL for The production API server, with the provided variables. +func NewServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServerBasePathVariable, noDefault ServerUrlTheProductionAPIServerNoDefaultVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) { + u := "https://{username}.gigantic-server.com:{port}/{basePath}" + + u = strings.ReplaceAll(u, "{basePath}", string(basePath)) + u = strings.ReplaceAll(u, "{noDefault}", string(noDefault)) + // TODO in the future, this will validate that the value is part of the ServerUrlTheProductionAPIServerPortVariable enum + 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 +} diff --git a/examples/generate/serverurls/gen_test.go b/examples/generate/serverurls/gen_test.go new file mode 100644 index 0000000000..2a2ecfb41a --- /dev/null +++ b/examples/generate/serverurls/gen_test.go @@ -0,0 +1,48 @@ +package serverurls + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestServerUrlTheProductionAPIServer(t *testing.T) { + t.Run("when no values are provided, it does not error", func(t *testing.T) { + serverUrl, err := NewServerUrlTheProductionAPIServer("", "", "", "") + require.NoError(t, err) + + assert.Equal(t, "https://.gigantic-server.com:/", serverUrl) + + // NOTE that ideally this should fail as it doesn't /seem/ to provide a valid URL, but it does seem to be valid + _, err = url.Parse(serverUrl) + require.NoError(t, err) + }) + + // TODO:when we validate enums, this will need more testing https://github.com/oapi-codegen/oapi-codegen/issues/2006 + t.Run("when values that are not part of the enum are provided, it does not error", func(t *testing.T) { + invalidPort := ServerUrlTheProductionAPIServerPortVariable("12345") + serverUrl, err := NewServerUrlTheProductionAPIServer( + ServerUrlTheProductionAPIServerBasePathVariableDefault, + ServerUrlTheProductionAPIServerNoDefaultVariable(""), + invalidPort, + ServerUrlTheProductionAPIServerUsernameVariableDefault, + ) + require.NoError(t, err) + + assert.Equal(t, "https://demo.gigantic-server.com:12345/v2", serverUrl) + }) + + t.Run("when default values are provided, it does not error", func(t *testing.T) { + serverUrl, err := NewServerUrlTheProductionAPIServer( + ServerUrlTheProductionAPIServerBasePathVariableDefault, + ServerUrlTheProductionAPIServerNoDefaultVariable(""), + ServerUrlTheProductionAPIServerPortVariableDefault, + ServerUrlTheProductionAPIServerUsernameVariableDefault, + ) + require.NoError(t, err) + + assert.Equal(t, "https://demo.gigantic-server.com:8443/v2", serverUrl) + }) +} 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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index facddb914d..6e602ea05a 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -202,6 +202,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { MergeImports(xGoTypeImports, imprts) } + var serverURLsDefinitions string + if opts.Generate.ServerURLs { + serverURLsDefinitions, err = GenerateServerURLs(t, spec) + if err != nil { + return "", fmt.Errorf("error generating Server URLs: %w", err) + } + } + var irisServerOut string if opts.Generate.IrisServer { irisServerOut, err = GenerateIrisServer(t, ops) @@ -326,6 +334,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) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 5608e227cd..4479acc1b1 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -126,6 +126,8 @@ 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"` } func (oo GenerateOptions) Validate() map[string]string { diff --git a/pkg/codegen/server_urls.go b/pkg/codegen/server_urls.go new file mode 100644 index 0000000000..d10c2d9f60 --- /dev/null +++ b/pkg/codegen/server_urls.go @@ -0,0 +1,81 @@ +package codegen + +import ( + "fmt" + "strconv" + "text/template" + + "github.com/getkin/kin-openapi/openapi3" +) + +const serverURLPrefix = "ServerUrl" +const serverURLSuffixIterations = 10 + +// 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 +} + +func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) { + names := make(map[string]*openapi3.Server) + + for _, server := range spec.Servers { + 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 + saved := false + // NOTE that we start at 1 on purpose, as + // + // ... ServerURLDevelopmentServer + // ... ServerURLDevelopmentServer1` + // + // reads better than: + // + // ... ServerURLDevelopmentServer + // ... ServerURLDevelopmentServer0 + for i := 1; i < 1+serverURLSuffixIterations; i++ { + suffixed := name + strconv.Itoa(i) + // and then store it if there's no conflict + if _, suffixConflict := names[suffixed]; !suffixConflict { + names[suffixed] = server + saved = true + break + } + } + + if saved { + continue + } + + // otherwise, error + return "", 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)) + i := 0 + for _, k := range keys { + servers[i] = ServerObjectDefinition{ + GoName: k, + OAPISchema: names[k], + } + i++ + } + + return GenerateTemplates([]string{"server-urls.tmpl"}, t, servers) +} diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index b9efe2cf45..49ee3aba64 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -23,6 +23,7 @@ import ( "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" ) @@ -295,6 +296,26 @@ func stripNewLines(s string) string { 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`) +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, ", ") +} + // TemplateFunctions is passed to the template engine, and we can call each // function here by keyName from the template code. var TemplateFunctions = template.FuncMap{ @@ -323,4 +344,6 @@ var TemplateFunctions = template.FuncMap{ "stripNewLines": stripNewLines, "sanitizeGoIdentity": SanitizeGoIdentity, "toGoComment": StringWithTypeNameToGoComment, + + "genServerURLWithVariablesFunctionParams": genServerURLWithVariablesFunctionParams, } diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl new file mode 100644 index 0000000000..f3599e5fa6 --- /dev/null +++ b/pkg/codegen/templates/server-urls.tmpl @@ -0,0 +1,61 @@ +{{ range . }} +{{ if eq 0 (len .OAPISchema.Variables) }} +{{/* URLs without variables are straightforward, so we'll create them a constant */}} +// {{ .GoName }} defines the Server URL for {{ .OAPISchema.Description }} +const {{ .GoName}} = "{{ .OAPISchema.URL }}" +{{ else }} +{{/* URLs with variables are not straightforward, as we may need multiple types, and so will model them as a function */}} + +{{/* first, we'll start by generating requisite types */}} + +{{ $goName := .GoName }} +{{ range $k, $v := .OAPISchema.Variables }} + {{ $prefix := printf "%s%sVariable" $goName ($k | ucFirst) }} + // {{ $prefix }} is the `{{ $k }}` variable for {{ $goName }} + type {{ $prefix }} string + {{ range $v.Enum }} + {{/* TODO this may result in broken generated code if any of the `enum` values are the literal value `default` https://github.com/oapi-codegen/oapi-codegen/issues/2003 */}} + // {{ $prefix }}{{ . | ucFirst }} is one of the accepted values for the `{{ $k }}` variable for {{ $goName }} + const {{ $prefix }}{{ . | ucFirst }} {{ $prefix }} = "{{ . }}" + {{ end }} + + {{/* TODO we should introduce a `Valid() error` method to enums https://github.com/oapi-codegen/oapi-codegen/issues/2006 */}} + + {{ if $v.Default }} + {{ if gt (len $v.Enum) 0 }} + {{/* if we have an enum, we should use the type defined for it for its default value + and reference the constant we've already defined for the value */}} + {{/* TODO this may result in broken generated code if any of the `enum` values are the literal value `default` https://github.com/oapi-codegen/oapi-codegen/issues/2003 */}} + {{/* TODO this may result in broken generated code if the `default` isn't found in `enum` (which is an issue with the spec) https://github.com/oapi-codegen/oapi-codegen/issues/2007 */}} + // {{ $prefix }}Default is the default choice, for the accepted values for the `{{ $k }}` variable for {{ $goName }} + const {{ $prefix }}Default {{ $prefix }} = {{ $prefix }}{{ $v.Default | ucFirst }} + {{ else }} + // {{ $prefix }}Default is the default value for the `{{ $k }}` variable for {{ $goName }} + const {{ $prefix }}Default = "{{ $v.Default }}" + {{ end }} + {{ end }} +{{ end }} + + +// New{{ .GoName }} constructs the Server URL for {{ .OAPISchema.Description }}, with the provided variables. +func New{{ .GoName }}({{ genServerURLWithVariablesFunctionParams .GoName .OAPISchema.Variables }}) (string, error) { + u := "{{ .OAPISchema.URL }}" + + {{ range $k, $v := .OAPISchema.Variables }} + {{- $placeholder := printf "{%s}" $k -}} + {{- if gt (len $v.Enum) 0 -}} + {{/* TODO https://github.com/oapi-codegen/oapi-codegen/issues/2006 */}} + // TODO in the future, this will validate that the value is part of the {{ printf "%s%sVariable" $goName ($k | ucFirst) }} enum + {{ end -}} + u = strings.ReplaceAll(u, "{{ $placeholder }}", string({{ $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 }} From a5da68435eb3251b151fd5dc5b8a2af99f7dbd68 Mon Sep 17 00:00:00 2001 From: BellStone <47925447+Park-Jongseok@users.noreply.github.com> Date: Sat, 28 Jun 2025 15:20:58 +0900 Subject: [PATCH 094/293] fix: correct anchor link for Request/response validation middleware The heading contained a slash (/) which GitHub removes when generating anchors, causing broken links. Changed to "Request Response Validation Middleware" to match existing anchor links in the document. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbeb6df669..a0783c0c13 100644 --- a/README.md +++ b/README.md @@ -3216,7 +3216,7 @@ 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/oapi-codegen/oapi-codegen/issues/1524) From 95920ff12e266b4c28ff7c0976937325a68f9ee0 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 09:21:07 +0100 Subject: [PATCH 095/293] docs(extensions): don't use `
` blocks in `` This is significantly hard to author, and makes it harder to read as rendered Markdown, too, so let's expand these out. We can retain the table view as a quick reference. --- README.md | 286 ++++++++++++++++++++++++------------------------------ 1 file changed, 127 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index a0783c0c13..5803263d30 100644 --- a/README.md +++ b/README.md @@ -2252,6 +2252,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: +
@@ -2261,9 +2263,6 @@ Extension - @@ -2276,8 +2275,122 @@ Example usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Description -Example usage -
Override the generated type definition (and optionally, add an import from another package)
-
+ +`x-go-type-skip-optional-pointer` + +
+Do not add a pointer type for optional fields in structs +
+ +`x-go-name` + + +Override the generated name of a field or a type +
+ +`x-go-type-name` + + +Override the generated name of a type +
+ +`x-omitempty` + + +Force the presence of the JSON tag `omitempty` on a field +
+ +`x-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. @@ -2336,21 +2449,7 @@ 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. @@ -2405,21 +2504,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. @@ -2476,21 +2561,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. @@ -2552,21 +2623,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. @@ -2621,21 +2678,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-go-json-ignore` - - - -When (un)marshaling JSON, ignore field(s) - - -
+### `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. @@ -2709,21 +2752,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. @@ -2780,21 +2809,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. @@ -2863,21 +2878,7 @@ type ClientTypeWithVarNamesExtension string You can see this in more detail in [the example code](examples/extensions/xenumnames/). -
- - - - - - -`x-deprecated-reason` - - - -Add a GoDoc deprecation warning to a type - - -
+### `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`. @@ -2935,21 +2936,7 @@ 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. @@ -3006,21 +2993,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. @@ -3064,12 +3038,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. From fca4d05b24ea6731b9d21826d4a4f63d99e979f9 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 09:25:03 +0100 Subject: [PATCH 096/293] docs(extensions): remove incorrectly duplicated note This appears to be an existing issue. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5803263d30..c77ea21090 100644 --- a/README.md +++ b/README.md @@ -2942,8 +2942,6 @@ Whether you like certain fields being ordered before others, or you want to perf 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 From 001735ee633ffa3e07245475b8779f1ee44fe4c6 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 09:28:16 +0100 Subject: [PATCH 097/293] docs(extensions): correct link to `x-omitempty` example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c77ea21090..ce9f665a5d 100644 --- a/README.md +++ b/README.md @@ -2676,7 +2676,7 @@ 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/xgojsonignore/). +You can see this in more detail in [the example code](examples/extensions/xomitempty/). ### `x-go-json-ignore` - when (un)marshaling JSON, ignore field(s) From e2f7dfd68135bcb87db86b8bf305d086465314cb Mon Sep 17 00:00:00 2001 From: Lukas Zapletal Date: Tue, 1 Apr 2025 15:26:16 +0200 Subject: [PATCH 098/293] feat(extensions): add support for `x-omitzero` One of the big improvements added in Go 1.24 is `omitzero`[0][1][2], which makes it possible to omit the "zero value" of a given Go type when marshaling to JSON, or if the `IsZero() bool` function on the type returns `true`. To make it possible for `oapi-codegen` to use this, we can wire in a new extension, `x-omitzero` which allows per-field tuning of this behaviour. This is something that is safe to generate alongside the `omitempty` tags[3]: > If both "omitempty" and "omitzero" are specified, the field will be omitted if the value is either empty or zero (or both). To validate this, we can add a new example for the extension, which provides testing of the expected behaviour. As this requires Go 1.24, we need to set up the boilerplate for a new module that only runs Go 1.24. Closes #1899. [0]: https://www.jvt.me/posts/2025/02/12/go-omitzero-124/ [1]: https://www.bytesizego.com/blog/go-124-omitzero [2]: https://antonz.org/go-1-24/#omit-zero-values-in-json [3]: https://pkg.go.dev/encoding/json --- README.md | 66 ++++++ examples/extensions/xomitzero/Makefile | 36 +++ examples/extensions/xomitzero/api.yaml | 53 +++++ examples/extensions/xomitzero/cfg.yaml | 8 + examples/extensions/xomitzero/generate.go | 3 + examples/extensions/xomitzero/go.mod | 32 +++ examples/extensions/xomitzero/go.sum | 167 +++++++++++++ examples/extensions/xomitzero/tools/tools.go | 8 + examples/extensions/xomitzero/types.gen.go | 37 +++ examples/extensions/xomitzero/types.go | 20 ++ examples/extensions/xomitzero/types_test.go | 236 +++++++++++++++++++ pkg/codegen/extension.go | 9 + pkg/codegen/schema.go | 46 ++-- 13 files changed, 702 insertions(+), 19 deletions(-) create mode 100644 examples/extensions/xomitzero/Makefile create mode 100644 examples/extensions/xomitzero/api.yaml create mode 100644 examples/extensions/xomitzero/cfg.yaml create mode 100644 examples/extensions/xomitzero/generate.go create mode 100644 examples/extensions/xomitzero/go.mod create mode 100644 examples/extensions/xomitzero/go.sum create mode 100644 examples/extensions/xomitzero/tools/tools.go create mode 100644 examples/extensions/xomitzero/types.gen.go create mode 100644 examples/extensions/xomitzero/types.go create mode 100644 examples/extensions/xomitzero/types_test.go diff --git a/README.md b/README.md index ce9f665a5d..4af7ddce1a 100644 --- a/README.md +++ b/README.md @@ -2324,6 +2324,17 @@ 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` @@ -2678,6 +2689,61 @@ 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/xomitempty/). +### `x-omitzero` - force the presence of the JSON tag `omitzero` on a field + +> [!NOTE] +> `omitzero` was added in Go 1.24. If you're not using Go 1.24 in your project, this won't work. + +In a case that you may want to add the JSON struct tag `omitzero` to types, you can use the `x-omitempty` extension. + +We can see this at play with the following schemas: + +```yaml +openapi: "3.0.0" +info: + version: 1.0.0 + title: x-omitempty +components: + schemas: + Client: + type: object + required: + - name + properties: + name: + type: string + id: + type: number + ClientWithExtension: + type: object + required: + - name + properties: + name: + type: string + id: + type: number + x-omitzero: true +``` + +From here, we now get two different models: + +```go +// Client defines model for Client. +type Client struct { + Id *float32 `json:"id,omitempty"` + Name string `json:"name"` +} + +// ClientWithExtension defines model for ClientWithExtension. +type ClientWithExtension struct { + Id *float32 `json:"id,omitempty,omitzero"` + Name string `json:"name"` +} +``` + +You can see this in more detail in [the example code](examples/extensions/xomitzero/). + ### `x-go-json-ignore` - when (un)marshaling JSON, ignore field(s) By default, `oapi-codegen` will generate `json:"..."` struct tags for all fields in a struct, so JSON (un)marshaling works. diff --git a/examples/extensions/xomitzero/Makefile b/examples/extensions/xomitzero/Makefile new file mode 100644 index 0000000000..e99db23781 --- /dev/null +++ b/examples/extensions/xomitzero/Makefile @@ -0,0 +1,36 @@ +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-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/examples/extensions/xomitzero/api.yaml b/examples/extensions/xomitzero/api.yaml new file mode 100644 index 0000000000..63b9b24c2b --- /dev/null +++ b/examples/extensions/xomitzero/api.yaml @@ -0,0 +1,53 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: x-omitempty +components: + schemas: + Client: + type: object + required: + - name + properties: + name: + type: string + id: + type: number + ClientWithExtension: + type: object + required: + - name + properties: + name: + type: string + id: + type: number + x-omitzero: true + ContainerTypeWithRequired: + type: object + properties: + has_is_zero: + $ref: "#/components/schemas/FieldWithCustomIsZeroMethod" + required: + - has_is_zero + ContainerTypeWithOptional: + type: object + properties: + has_is_zero: + $ref: "#/components/schemas/FieldWithCustomIsZeroMethod" + FieldWithCustomIsZeroMethod: + type: object + properties: + id: + type: string + value: + type: number + x-omitzero: true + FieldWithOmitZeroOnRequiredField: + type: object + properties: + id: + type: string + x-omitzero: true + required: + - id diff --git a/examples/extensions/xomitzero/cfg.yaml b/examples/extensions/xomitzero/cfg.yaml new file mode 100644 index 0000000000..bcec1dd3c6 --- /dev/null +++ b/examples/extensions/xomitzero/cfg.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=../../../configuration-schema.json +package: xomitzero +output: types.gen.go +generate: + models: true +output-options: + # to make sure that all types are generated, even if they're unreferenced + skip-prune: true diff --git a/examples/extensions/xomitzero/generate.go b/examples/extensions/xomitzero/generate.go new file mode 100644 index 0000000000..70b6c27164 --- /dev/null +++ b/examples/extensions/xomitzero/generate.go @@ -0,0 +1,3 @@ +package xomitzero + +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod new file mode 100644 index 0000000000..65438474ee --- /dev/null +++ b/examples/extensions/xomitzero/go.mod @@ -0,0 +1,32 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/extensions/xomitzero + +go 1.24 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +require ( + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.10.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/getkin/kin-openapi v0.128.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 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum new file mode 100644 index 0000000000..e8c27f0da0 --- /dev/null +++ b/examples/extensions/xomitzero/go.sum @@ -0,0 +1,167 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/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/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/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.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/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/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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +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/examples/extensions/xomitzero/tools/tools.go b/examples/extensions/xomitzero/tools/tools.go new file mode 100644 index 0000000000..8615cb4c57 --- /dev/null +++ b/examples/extensions/xomitzero/tools/tools.go @@ -0,0 +1,8 @@ +//go:build tools +// +build tools + +package tools + +import ( + _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" +) diff --git a/examples/extensions/xomitzero/types.gen.go b/examples/extensions/xomitzero/types.gen.go new file mode 100644 index 0000000000..fe5e927d95 --- /dev/null +++ b/examples/extensions/xomitzero/types.gen.go @@ -0,0 +1,37 @@ +// Package xomitzero provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. +package xomitzero + +// Client defines model for Client. +type Client struct { + Id *float32 `json:"id,omitempty"` + Name string `json:"name"` +} + +// ClientWithExtension defines model for ClientWithExtension. +type ClientWithExtension struct { + Id *float32 `json:"id,omitempty,omitzero"` + Name string `json:"name"` +} + +// ContainerTypeWithOptional defines model for ContainerTypeWithOptional. +type ContainerTypeWithOptional struct { + HasIsZero *FieldWithCustomIsZeroMethod `json:"has_is_zero,omitempty,omitzero"` +} + +// ContainerTypeWithRequired defines model for ContainerTypeWithRequired. +type ContainerTypeWithRequired struct { + HasIsZero FieldWithCustomIsZeroMethod `json:"has_is_zero,omitzero"` +} + +// FieldWithCustomIsZeroMethod defines model for FieldWithCustomIsZeroMethod. +type FieldWithCustomIsZeroMethod struct { + Id *string `json:"id,omitempty"` + Value *float32 `json:"value,omitempty"` +} + +// FieldWithOmitZeroOnRequiredField defines model for FieldWithOmitZeroOnRequiredField. +type FieldWithOmitZeroOnRequiredField struct { + Id string `json:"id,omitzero"` +} diff --git a/examples/extensions/xomitzero/types.go b/examples/extensions/xomitzero/types.go new file mode 100644 index 0000000000..fed32fb8f0 --- /dev/null +++ b/examples/extensions/xomitzero/types.go @@ -0,0 +1,20 @@ +package xomitzero + +type isZero interface { + IsZero() bool +} + +var _ isZero = (*FieldWithCustomIsZeroMethod)(nil) + +func (z FieldWithCustomIsZeroMethod) IsZero() bool { + // NOTE that this is intentionally not a "normal" use of the function, but is a way to indicate that the `IsZero` used here can be anything arbitrary + if z.Id == nil { + return false + } + + if *z.Id != "this is a zero value, for some weird reason!" { + return false + } + + return true +} diff --git a/examples/extensions/xomitzero/types_test.go b/examples/extensions/xomitzero/types_test.go new file mode 100644 index 0000000000..496d345d3c --- /dev/null +++ b/examples/extensions/xomitzero/types_test.go @@ -0,0 +1,236 @@ +package xomitzero + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestClient_WithOmitEmpty(t *testing.T) { + t.Run("with a `string`, without `omitempty`", func(t *testing.T) { + t.Run("zero value Name does not get omitted", func(t *testing.T) { + client := Client{ + Name: "", + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "name")) + }) + + t.Run("value Name does not get omitted", func(t *testing.T) { + client := Client{ + Name: "some value", + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "name")) + }) + }) + + t.Run("with a `*float32` with `omitempty`", func(t *testing.T) { + var zeroValue float32 + + t.Run("nil pointer ID gets omitted", func(t *testing.T) { + client := Client{ + Id: nil, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "id")) + }) + + t.Run("pointer to zero value ID does not get omitted", func(t *testing.T) { + client := Client{ + Id: &zeroValue, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "id")) + }) + + t.Run("pointer to value ID does not get omitted", func(t *testing.T) { + client := Client{ + Id: &zeroValue, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "id")) + }) + }) +} + +func TestClientWithExtension_WithOmitZero(t *testing.T) { + t.Run("with a `string`, without `omitzero`", func(t *testing.T) { + t.Run("zero value Name does not get omitted", func(t *testing.T) { + client := ClientWithExtension{ + Name: "", + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "name")) + }) + + t.Run("value Name does not get omitted", func(t *testing.T) { + client := ClientWithExtension{ + Name: "some value", + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "name")) + }) + }) + + t.Run("with a `*float32` with `omitzero`", func(t *testing.T) { + var zeroValue float32 + + t.Run("nil pointer ID gets omitted", func(t *testing.T) { + client := ClientWithExtension{ + Id: nil, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "id")) + }) + + t.Run("pointer to zero value ID does not get omitted", func(t *testing.T) { + client := ClientWithExtension{ + Id: &zeroValue, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "id")) + }) + + t.Run("pointer to value ID does not get omitted", func(t *testing.T) { + client := ClientWithExtension{ + Id: &zeroValue, + } + + b, err := json.Marshal(client) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "id")) + }) + }) +} + +func TestContainerTypeWithRequired(t *testing.T) { + t.Run("zero value on HasIsZero does not get omitted", func(t *testing.T) { + container := ContainerTypeWithRequired{ + HasIsZero: FieldWithCustomIsZeroMethod{}, + } + + b, err := json.Marshal(container) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "has_is_zero")) + }) + + t.Run("value defined as zero value by IsZero on HasIsZero gets omitted", func(t *testing.T) { + magicIDValue := "this is a zero value, for some weird reason!" + + container := ContainerTypeWithRequired{ + HasIsZero: FieldWithCustomIsZeroMethod{ + Id: &magicIDValue, + }, + } + + b, err := json.Marshal(container) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "has_is_zero")) + }) +} + +func TestContainerTypeWithOptional(t *testing.T) { + t.Run("zero value (nil pointer) on HasIsZero gets omitted", func(t *testing.T) { + container := ContainerTypeWithOptional{ + HasIsZero: nil, + } + + b, err := json.Marshal(container) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "has_is_zero")) + }) + + t.Run("value (pointer to zero value of FieldWithCustomIsZeroMethod) on HasIsZero does not get omitted", func(t *testing.T) { + container := ContainerTypeWithOptional{ + HasIsZero: &FieldWithCustomIsZeroMethod{}, + } + + b, err := json.Marshal(container) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "has_is_zero")) + }) + + t.Run("value defined as zero value by IsZero on HasIsZero gets omitted", func(t *testing.T) { + magicIDValue := "this is a zero value, for some weird reason!" + + container := ContainerTypeWithOptional{ + HasIsZero: &FieldWithCustomIsZeroMethod{ + Id: &magicIDValue, + }, + } + + b, err := json.Marshal(container) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "has_is_zero")) + }) +} + +func TestFieldWithOmitZeroOnRequiredField(t *testing.T) { + t.Run("zero value (empty string) on Id gets omitted", func(t *testing.T) { + field := FieldWithOmitZeroOnRequiredField{ + Id: "", + } + + b, err := json.Marshal(field) + require.NoError(t, err) + + assert.False(t, jsonContainsKey(b, "id")) + }) + + t.Run("value for Id not get omitted", func(t *testing.T) { + field := FieldWithOmitZeroOnRequiredField{ + Id: "value", + } + + b, err := json.Marshal(field) + require.NoError(t, err) + + assert.True(t, jsonContainsKey(b, "id")) + }) +} + +// jsonContainsKey checks if the given JSON object contains the specified key at the top level. +func jsonContainsKey(b []byte, key string) bool { + var m map[string]any + if err := json.Unmarshal(b, &m); err != nil { + return false + } + _, ok := m[key] + return ok +} diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index f5ef5ef4d2..579d8a17c9 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -18,6 +18,7 @@ const ( 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" @@ -60,6 +61,14 @@ func extParseOmitEmpty(extPropValue interface{}) (bool, error) { return omitEmpty, nil } +func extParseOmitZero(extPropValue interface{}) (bool, error) { + omitZero, ok := extPropValue.(bool) + if !ok { + return false, fmt.Errorf("failed to convert type: %T", extPropValue) + } + return omitZero, nil +} + func extExtraTags(extPropValue interface{}) (map[string]string, error) { tagsI, ok := extPropValue.(map[string]interface{}) if !ok { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index d2e64f9805..47883ab0c4 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -674,6 +674,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 { @@ -724,31 +731,32 @@ func GenFieldsFromProperties(props []Property) []string { omitEmpty = shouldOmitEmpty } - // Support x-omitempty + omitZero := false + + // 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 globalState.options.OutputOptions.EnableYamlTags { - fieldTags["yaml"] = p.JsonFieldName - } - if p.NeedsFormTag { - fieldTags["form"] = p.JsonFieldName - } - } else { - fieldTags["json"] = p.JsonFieldName + ",omitempty" - if globalState.options.OutputOptions.EnableYamlTags { - fieldTags["yaml"] = 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 From 739f502e9339d84fedfafc3513f51c15a6e6122d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 09:35:59 +0100 Subject: [PATCH 099/293] docs(extensions): remove incorrect duplicated comment --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 4af7ddce1a..375e56c963 100644 --- a/README.md +++ b/README.md @@ -2685,8 +2685,6 @@ 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/). ### `x-omitzero` - force the presence of the JSON tag `omitzero` on a field From e93501d11774bb6e327c17a77666e968830907b8 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 10:25:24 +0100 Subject: [PATCH 100/293] chore(examples): add tests for `preferskipoptionalpointer` As part of a future change, we're adding the Output Option `prefer-skip-optional-pointer-with-omitzero`. As part of this, we want to make sure that the existing behaviour, with the `omitempty` default, works as expected. --- .../preferskipoptionalpointer/gen_test.go | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 examples/output-options/preferskipoptionalpointer/gen_test.go diff --git a/examples/output-options/preferskipoptionalpointer/gen_test.go b/examples/output-options/preferskipoptionalpointer/gen_test.go new file mode 100644 index 0000000000..26a12a6147 --- /dev/null +++ b/examples/output-options/preferskipoptionalpointer/gen_test.go @@ -0,0 +1,65 @@ +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")) + }) +} + +// 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 +} From fad490f90982ec216cd2f9a00541cc3799af1da9 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 10:42:39 +0100 Subject: [PATCH 101/293] fix(output-options): obey `prefer-skip-optional-pointer` in reference types --- pkg/codegen/schema.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 47883ab0c4..46ebe81868 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -270,10 +270,11 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { sref.Ref, err) } return Schema{ - GoType: refType, - Description: schema.Description, - DefineViaAlias: true, - OAPISchema: schema, + GoType: refType, + Description: schema.Description, + DefineViaAlias: true, + OAPISchema: schema, + SkipOptionalPointer: globalState.options.OutputOptions.PreferSkipOptionalPointer, }, nil } From f2bf24967fc3d873178df30e02df7ca2c72b73c9 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 10:25:36 +0100 Subject: [PATCH 102/293] chore(examples): add nested type to tests This builds on top of the previous commit's fix to ensure that it gets generated correctly. --- .../preferskipoptionalpointer/api.yaml | 6 +++++ .../preferskipoptionalpointer/gen.go | 5 ++++ .../preferskipoptionalpointer/gen_test.go | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/examples/output-options/preferskipoptionalpointer/api.yaml b/examples/output-options/preferskipoptionalpointer/api.yaml index 3ba1bfdd1b..0395e8961f 100644 --- a/examples/output-options/preferskipoptionalpointer/api.yaml +++ b/examples/output-options/preferskipoptionalpointer/api.yaml @@ -31,3 +31,9 @@ components: 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' diff --git a/examples/output-options/preferskipoptionalpointer/gen.go b/examples/output-options/preferskipoptionalpointer/gen.go index 01749ecddc..0d6a9fde25 100644 --- a/examples/output-options/preferskipoptionalpointer/gen.go +++ b/examples/output-options/preferskipoptionalpointer/gen.go @@ -23,3 +23,8 @@ type ClientWithExtension struct { // 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"` +} diff --git a/examples/output-options/preferskipoptionalpointer/gen_test.go b/examples/output-options/preferskipoptionalpointer/gen_test.go index 26a12a6147..edcb5853ec 100644 --- a/examples/output-options/preferskipoptionalpointer/gen_test.go +++ b/examples/output-options/preferskipoptionalpointer/gen_test.go @@ -54,6 +54,32 @@ func TestClient(t *testing.T) { }) } +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")) + }) +} + // 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 From de34b881ef513002afee0c86e2c9ad7d7e9ad1b1 Mon Sep 17 00:00:00 2001 From: kf-pineapple <149494459+kf-pineapple@users.noreply.github.com> Date: Tue, 15 Jul 2025 19:46:11 +0900 Subject: [PATCH 103/293] fix: create directories if they do not exist before writing output file (#1994) As noted in #1052, if the parent directory of the output file doesn't exist, it will be automatically created before writing the generated code. This prevents errors if the specified output path contains a non-existent directory. Closes #1052. --- cmd/oapi-codegen/oapi-codegen.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index c41f3718d3..78bea5b1e3 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -319,6 +319,9 @@ func main() { } if opts.OutputFile != "" { + if err := os.MkdirAll(filepath.Dir(opts.OutputFile), 0o755); err != nil { + errExit("error unable to create directory: %s\n", err) + } err = os.WriteFile(opts.OutputFile, []byte(code), 0o644) if err != nil { errExit("error writing generated code to file: %s\n", err) From f6889c0a22826599abcaceb89c1b93e28fb5fe05 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 11:31:09 +0100 Subject: [PATCH 104/293] chore: rename variable --- pkg/codegen/schema.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 46ebe81868..1e762ca725 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -705,8 +705,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 } } From 5369d1f176b22eddb4005b679cd3191adea81d81 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 11:36:25 +0100 Subject: [PATCH 105/293] chore(examples): add a deprecated field without any reason In the case that we have a field deprecated, but no reason, the deprecation comment isn't ideal. Let's document it now, and improve it afterwards. --- examples/extensions/xdeprecatedreason/api.yaml | 4 ++++ examples/extensions/xdeprecatedreason/gen.go | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) 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..b35e105e87 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: + DeprecatedWithoutReason *string `json:"deprecated_without_reason,omitempty"` + Id *float32 `json:"id,omitempty"` // Deprecated: Don't use because reasons Name string `json:"name"` } From 7688c8d1e189df70d51ec0e7a685304b426bb161 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 11:38:46 +0100 Subject: [PATCH 106/293] feat(x-deprecated-reason): add default deprecation message In the case that we have a field deprecated, but no reason, the deprecation comment isn't ideal. We can improve this by adding a default message in the case of no `x-deprecated-reason`. --- examples/extensions/xdeprecatedreason/gen.go | 2 +- internal/test/schemas/schemas.gen.go | 4 ++-- pkg/codegen/utils.go | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/extensions/xdeprecatedreason/gen.go b/examples/extensions/xdeprecatedreason/gen.go index b35e105e87..3855905f92 100644 --- a/examples/extensions/xdeprecatedreason/gen.go +++ b/examples/extensions/xdeprecatedreason/gen.go @@ -11,7 +11,7 @@ type Client struct { // ClientWithExtension defines model for ClientWithExtension. type ClientWithExtension struct { - // Deprecated: + // 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 diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 09efa4a018..1a7f9e61b7 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -52,11 +52,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"` diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 6ecf27433c..5326e672bf 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -881,6 +881,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, "") From ac399537d6ae443dbdb50047f9b9de1706607e03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:33:11 +0000 Subject: [PATCH 107/293] chore(deps): update module github.com/golangci/golangci-lint to v2.2.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8c63b973f9..777160b716 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) v2.1.6 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v2.2.2 .PHONY: tools tools: $(GOBIN)/golangci-lint From 364997d66022a4ea83e6737a0a072b0011d25a3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 13:21:02 +0000 Subject: [PATCH 108/293] fix(deps): update module github.com/getkin/kin-openapi to v0.131.0 [security] --- examples/authenticated-api/stdhttp/go.mod | 7 ++++--- examples/authenticated-api/stdhttp/go.sum | 10 ++++++---- examples/extensions/xomitzero/go.mod | 5 +++-- examples/extensions/xomitzero/go.sum | 10 ++++++---- examples/go.mod | 7 ++++--- examples/go.sum | 10 ++++++---- examples/minimal-server/stdhttp-go-tool/go.mod | 5 +++-- examples/minimal-server/stdhttp-go-tool/go.sum | 10 ++++++---- examples/minimal-server/stdhttp/go.mod | 7 ++++--- examples/minimal-server/stdhttp/go.sum | 10 ++++++---- examples/petstore-expanded/stdhttp/go.mod | 7 ++++--- examples/petstore-expanded/stdhttp/go.sum | 10 ++++++---- go.mod | 7 ++++--- go.sum | 10 ++++++---- internal/test/go.mod | 7 ++++--- internal/test/go.sum | 10 ++++++---- internal/test/strict-server/stdhttp/go.mod | 7 ++++--- internal/test/strict-server/stdhttp/go.sum | 10 ++++++---- 18 files changed, 88 insertions(+), 61 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 935aecbefe..7681ac6450 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -1,11 +1,11 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp -go 1.22 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.131.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 @@ -21,7 +21,6 @@ require ( 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 @@ -30,6 +29,8 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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 diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index b9df64e432..b8bbc4262c 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -42,8 +42,6 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -77,6 +75,10 @@ github.com/oapi-codegen/nethttp-middleware v1.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index 65438474ee..43cef8c3da 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -12,13 +12,14 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/getkin/kin-openapi v0.131.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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index e8c27f0da0..4ca3b86203 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -53,6 +51,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/examples/go.mod b/examples/go.mod index eb2bfe37e5..a1033987e9 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,11 +1,11 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.22 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.131.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 @@ -56,7 +56,6 @@ require ( 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/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -83,6 +82,8 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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 diff --git a/examples/go.sum b/examples/go.sum index e783fc97e3..84b37d9780 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -52,8 +52,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -118,8 +118,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO 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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -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/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= @@ -213,6 +211,10 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index e122ee9d19..75fb87ccaf 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -8,14 +8,15 @@ tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/getkin/kin-openapi v0.131.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/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index e8c27f0da0..4ca3b86203 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -53,6 +51,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 6bf90d508f..06f0b16f09 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp -go 1.22 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ @@ -8,13 +8,14 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/getkin/kin-openapi v0.131.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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index e8c27f0da0..4ca3b86203 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -53,6 +51,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 4e430e7599..d5fe923d14 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -1,11 +1,11 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp -go 1.22 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.131.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 @@ -21,10 +21,11 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 3cee4a7c00..54fef92f7d 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -43,8 +43,6 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 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/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= @@ -68,6 +66,10 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/go.mod b/go.mod index 12fdc6a787..fd26a3b1cd 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.22 +go 1.22.5 require ( - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.131.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.10.0 golang.org/x/mod v0.17.0 @@ -18,10 +18,11 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/go.sum b/go.sum index e8c27f0da0..4ca3b86203 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -53,6 +51,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 2ee32358df..46bbce3b72 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,11 +1,11 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.22 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.128.0 + github.com/getkin/kin-openapi v0.131.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 @@ -49,7 +49,6 @@ require ( 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/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -71,6 +70,8 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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 diff --git a/internal/test/go.sum b/internal/test/go.sum index e551d7c7a4..76720e908b 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -51,8 +51,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -117,8 +117,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO 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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -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/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= @@ -193,6 +191,10 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 1b32924c17..75df555aa3 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -1,13 +1,13 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp -go 1.22 +go 1.22.5 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.128.0 + github.com/getkin/kin-openapi v0.131.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 @@ -22,10 +22,11 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 970b345a42..6a12a64729 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -41,8 +41,6 @@ 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/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/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= @@ -64,6 +62,10 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= From c6493abd9a8e5dbbc7583619cbeef276da4c3428 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:11:40 +0000 Subject: [PATCH 109/293] fix(deps): update module github.com/getkin/kin-openapi to v0.132.0 --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 4 ++-- examples/extensions/xomitzero/go.mod | 2 +- examples/extensions/xomitzero/go.sum | 4 ++-- examples/go.mod | 2 +- examples/go.sum | 4 ++-- examples/minimal-server/stdhttp-go-tool/go.mod | 2 +- examples/minimal-server/stdhttp-go-tool/go.sum | 4 ++-- examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 18 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 7681ac6450..4a60a8451a 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.131.0 + github.com/getkin/kin-openapi v0.132.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 diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index b8bbc4262c..712a223d85 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index 43cef8c3da..63a0603f14 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -12,7 +12,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.131.0 // indirect + github.com/getkin/kin-openapi v0.132.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index 4ca3b86203..d6b9515854 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/examples/go.mod b/examples/go.mod index a1033987e9..b47de77c71 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.131.0 + github.com/getkin/kin-openapi v0.132.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 diff --git a/examples/go.sum b/examples/go.sum index 84b37d9780..809bd7b603 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -52,8 +52,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 75fb87ccaf..894abfa890 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -8,7 +8,7 @@ tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.131.0 // indirect + github.com/getkin/kin-openapi v0.132.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index 4ca3b86203..d6b9515854 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 06f0b16f09..c7482feec2 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -8,7 +8,7 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.131.0 // indirect + github.com/getkin/kin-openapi v0.132.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 4ca3b86203..d6b9515854 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index d5fe923d14..c5621598c1 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.131.0 + github.com/getkin/kin-openapi v0.132.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 diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 54fef92f7d..dd7bd07c8b 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/go.mod b/go.mod index fd26a3b1cd..f7b97aa03d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.22.5 require ( - github.com/getkin/kin-openapi v0.131.0 + github.com/getkin/kin-openapi v0.132.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.10.0 golang.org/x/mod v0.17.0 diff --git a/go.sum b/go.sum index 4ca3b86203..d6b9515854 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 46bbce3b72..f9f65fd96c 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.131.0 + github.com/getkin/kin-openapi v0.132.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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 76720e908b..5d3c0a7e6c 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -51,8 +51,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 75df555aa3..d8f9e9d0fa 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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.131.0 + github.com/getkin/kin-openapi v0.132.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 diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 6a12a64729..4aaab49fca 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= From b72bb2a9235c198e39695f1e9652a0e3c26d053e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 11:58:57 +0100 Subject: [PATCH 110/293] feat(output-options): allow using `omitzero` with `prefer-skip-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. As noted in #1899, now Go 1.24+ has the `omitzero` JSON tag for marshaling only when a type is not its zero value. As we support generating `omitzero` JSON tags via the `x-omitzero` extension, we can build on top of this to consider allowing the use of `omitzero` when using the newly added global Output Option, `prefer-skip-optional-pointer` to tune this behaviour. This introduces a new Output Option, `prefer-skip-optional-pointer-with-omitzero`, which mirrors behaviour from `prefer-skip-optional-pointer`, but produces an `omitzero` flag for any skipped pointer types, to not marshal the type if the zero value. This allows folks using Go 1.24+ to much more ergonomically work with different (optional) types, while allowing `omitzero` to simplify (un)marshalling. Right now, we don't have a straightforward means of enforcing/warning that `oapi-codegen` is being generated into a non-Go-1.24+ project, so we'll only document the behaviour. Closes #1899. --- configuration-schema.json | 5 + .../Makefile | 36 ++++ .../api.yaml | 44 +++++ .../cfg.yaml | 10 ++ .../gen.go | 33 ++++ .../gen_test.go | 91 ++++++++++ .../generate.go | 3 + .../go.mod | 32 ++++ .../go.sum | 167 ++++++++++++++++++ .../tools/tools.go | 8 + pkg/codegen/configuration.go | 6 + pkg/codegen/schema.go | 5 + 12 files changed, 440 insertions(+) create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/Makefile create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/api.yaml create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/cfg.yaml create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/gen.go create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/gen_test.go create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/generate.go create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/go.mod create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/go.sum create mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/tools/tools.go diff --git a/configuration-schema.json b/configuration-schema.json index 0b35d7e657..9047914479 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -243,6 +243,11 @@ "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.", diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile b/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile new file mode 100644 index 0000000000..e99db23781 --- /dev/null +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile @@ -0,0 +1,36 @@ +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-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) 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/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod new file mode 100644 index 0000000000..17ed70f6cc --- /dev/null +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -0,0 +1,32 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/output-options/preferskipoptionalpointerwithomitzero + +go 1.24 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +require ( + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.10.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/getkin/kin-openapi v0.128.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 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum new file mode 100644 index 0000000000..e8c27f0da0 --- /dev/null +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -0,0 +1,167 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/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/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/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.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/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/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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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/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= +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.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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +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/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/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 4479acc1b1..1d9ff3eaea 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -292,6 +292,12 @@ type OutputOptions struct { // 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"` } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 1e762ca725..4f983d1219 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -734,6 +734,11 @@ func GenFieldsFromProperties(props []Property) []string { omitZero := false + // default, but allow turning of + if shouldOmitEmpty && p.Schema.SkipOptionalPointer && globalState.options.OutputOptions.PreferSkipOptionalPointerWithOmitzero { + omitZero = true + } + // Support x-omitempty and x-omitzero if extOmitEmptyValue, ok := p.Extensions[extPropOmitEmpty]; ok { if xValue, err := extParseOmitEmpty(extOmitEmptyValue); err == nil { From 22ccd0503a104b308838c0cb224f6bfc9e99d820 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 13:16:46 +0100 Subject: [PATCH 111/293] docs(output-options): document how to skip the "optional pointer" As a follow-up from the two options we've recently introduced for this. This adds an anchor so we can reference it more easily than the GitHub-generated name for the long heading. --- README.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/README.md b/README.md index 375e56c963..af9e383fca 100644 --- a/README.md +++ b/README.md @@ -2462,6 +2462,8 @@ You can see this in more detail in [the example code](examples/extensions/xgotyp ### `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. > @@ -3732,6 +3734,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-with-omitzero`, 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. From f4a544ee8435f4707d2507d1201f7e6ac9b4b999 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 15:44:02 +0100 Subject: [PATCH 112/293] fixup! feat(output-options): allow using `omitzero` with `prefer-skip-optional-pointer` We should have rebased #2023 before this was merged, as the versions were outdated. --- .../preferskipoptionalpointerwithomitzero/go.mod | 5 +++-- .../preferskipoptionalpointerwithomitzero/go.sum | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod index 17ed70f6cc..d8ff6c8582 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -12,13 +12,14 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/getkin/kin-openapi v0.132.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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum index e8c27f0da0..d6b9515854 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 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= @@ -35,8 +35,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -53,6 +51,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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= From 8e7938e6b5c0de1007c12fd8806862dda5a0e65f Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 16:17:33 +0100 Subject: [PATCH 113/293] docs(client): document known issue with duplicated `Response` models Closes #1965. --- README.md | 97 +++++++++ examples/clienttypenameclash/api.yaml | 34 +++ examples/clienttypenameclash/cfg.yaml | 8 + examples/clienttypenameclash/client.gen.go | 239 +++++++++++++++++++++ examples/clienttypenameclash/generate.go | 3 + 5 files changed, 381 insertions(+) create mode 100644 examples/clienttypenameclash/api.yaml create mode 100644 examples/clienttypenameclash/cfg.yaml create mode 100644 examples/clienttypenameclash/client.gen.go create mode 100644 examples/clienttypenameclash/generate.go diff --git a/README.md b/README.md index af9e383fca..415795f82b 100644 --- a/README.md +++ b/README.md @@ -1796,6 +1796,103 @@ However, for more complex URLs that defined `variables` in them, we generate the 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. 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..219a2a0d4d --- /dev/null +++ b/examples/clienttypenameclash/client.gen.go @@ -0,0 +1,239 @@ +// 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("PUT", 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 +} + +// 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 +} + +// UpdateClientWithResponse request returning *UpdateClientResp +func (c *ClientWithResponses) UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResp, error) { + rsp, err := c.UpdateClient(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseUpdateClientResp(rsp) +} + +// ParseUpdateClientResp parses an HTTP response from a UpdateClientWithResponse call +func ParseUpdateClientResp(rsp *http.Response) (*UpdateClientResp, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UpdateClientResp{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest UpdateClientResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + } + + return response, nil +} diff --git a/examples/clienttypenameclash/generate.go b/examples/clienttypenameclash/generate.go new file mode 100644 index 0000000000..e9c9a42f86 --- /dev/null +++ b/examples/clienttypenameclash/generate.go @@ -0,0 +1,3 @@ +package client + +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml From 13eea66b2bf673f56fc270af5699830187d01daf Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 15 Jul 2025 16:39:40 +0100 Subject: [PATCH 114/293] docs(additional-initialisms): add a usage example --- .../output-options/additionalinitialisms/api.yaml | 14 ++++++++++++++ .../output-options/additionalinitialisms/cfg.yaml | 11 +++++++++++ .../output-options/additionalinitialisms/gen.go | 10 ++++++++++ .../additionalinitialisms/generate.go | 3 +++ 4 files changed, 38 insertions(+) create mode 100644 examples/output-options/additionalinitialisms/api.yaml create mode 100644 examples/output-options/additionalinitialisms/cfg.yaml create mode 100644 examples/output-options/additionalinitialisms/gen.go create mode 100644 examples/output-options/additionalinitialisms/generate.go 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 From 635bb4e59de33ccf8c447d53a0c50fa61d9ae8b8 Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Wed, 16 Jul 2025 17:00:01 +1000 Subject: [PATCH 115/293] Fix bullet point line `prefer-skip-optional-pointer-with-omitzero` typo in `README.md` (#2028) Fix bulletpoint line `prefer-skip-optional-pointer-with-omitzero` typo - reference back to `prefer-skip-optional-pointer` Co-authored-by: Jamie Tanna --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 415795f82b..564d39f903 100644 --- a/README.md +++ b/README.md @@ -3837,10 +3837,10 @@ One of the key things `oapi-codegen` does is to use an "optional pointer", follo 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: +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-with-omitzero`, any optional fields are generated with an `omitzero` JSON tag. **Requires Go 1.24+** +- `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). From 62fec2f45dbc666e4e9595fbc7bd5cda9cd5ea24 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 17 Jul 2025 16:11:14 +0100 Subject: [PATCH 116/293] chore(renovate): don't exclude `examples` and `internal/test` We're using `:default`[0] from our configuration, which then excludes our `examples` and `internal/test` directories[1][2][3]. It is handy for us to keep these dependencies up-to-date, so we should override the `ignorePaths` for Go dependencies. [0]: https://github.com/oapi-codegen/renovate-config/blob/d63ca7f61facd164040be09ee8a32090435cef57/default.json#L4 [1]: https://docs.renovatebot.com/presets-config/#configbest-practices [2]: https://docs.renovatebot.com/presets-config/#configrecommended [3]: https://docs.renovatebot.com/presets-default/#ignoremodulesandtests --- renovate.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index cf87ba3dd6..cb5f9a2063 100644 --- a/renovate.json +++ b/renovate.json @@ -2,5 +2,8 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "local>oapi-codegen/renovate-config" - ] + ], + "gomod": { + "ignorePaths": [] + } } From 702cc9178842ef30e8ea8b1ec3aeb9637fa3895f Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Sat, 26 Jul 2025 03:22:02 +1000 Subject: [PATCH 117/293] fix(output-options): correctly reference `x-go-type-skip-optional-pointer` in `allOf` (#2042) If using the global `prefer-skip-optional-pointer: true` alongside a field-level `x-go-type-skip-optional-pointer: false` on a type that's referenced by an `allOf`, we don't correctly follow the field-level type reference and override the value. This correctly generates the type. Co-authored-by: Jamie Tanna --- .../preferskipoptionalpointer/api.yaml | 28 +++++++++++++++ .../preferskipoptionalpointer/gen.go | 16 +++++++++ .../preferskipoptionalpointer/gen_test.go | 36 +++++++++++++++++++ pkg/codegen/schema.go | 31 ++++++++-------- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/examples/output-options/preferskipoptionalpointer/api.yaml b/examples/output-options/preferskipoptionalpointer/api.yaml index 0395e8961f..8903309983 100644 --- a/examples/output-options/preferskipoptionalpointer/api.yaml +++ b/examples/output-options/preferskipoptionalpointer/api.yaml @@ -37,3 +37,31 @@ components: 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/gen.go b/examples/output-options/preferskipoptionalpointer/gen.go index 0d6a9fde25..623bf9455f 100644 --- a/examples/output-options/preferskipoptionalpointer/gen.go +++ b/examples/output-options/preferskipoptionalpointer/gen.go @@ -28,3 +28,19 @@ type ClientWithExtension struct { 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 index edcb5853ec..3a5f5b4ed8 100644 --- a/examples/output-options/preferskipoptionalpointer/gen_test.go +++ b/examples/output-options/preferskipoptionalpointer/gen_test.go @@ -80,6 +80,42 @@ func TestNestedType(t *testing.T) { }) } +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 diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 4f983d1219..1d03fbdd0e 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -260,6 +260,18 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { schema := sref.Value + // 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 := schema.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) { @@ -274,15 +286,14 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { Description: schema.Description, DefineViaAlias: true, OAPISchema: schema, - SkipOptionalPointer: globalState.options.OutputOptions.PreferSkipOptionalPointer, + SkipOptionalPointer: skipOptionalPointer, }, nil } outSchema := Schema{ - Description: schema.Description, - OAPISchema: schema, - // NOTE that SkipOptionalPointer will be defaulted to the global value, but can be overridden on a per-type/-field basis - SkipOptionalPointer: globalState.options.OutputOptions.PreferSkipOptionalPointer, + Description: schema.Description, + OAPISchema: schema, + SkipOptionalPointer: skipOptionalPointer, } // AllOf is interesting, and useful. It's the union of a number of other @@ -298,16 +309,6 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return mergedSchema, 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) - if err != nil { - return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoTypeSkipOptionalPointer, err) - } - outSchema.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 { From 80635cd45a2021c18b04888fef461ff8123ba5c5 Mon Sep 17 00:00:00 2001 From: Chai Landau <112015853+chailandau@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:46:15 -0400 Subject: [PATCH 118/293] docs(sponsors): update Speakeasy logo (#2049) --- .github/sponsors/speakeasy-dark.svg | 36 ++++++++++++++-------------- .github/sponsors/speakeasy-light.svg | 36 +++++++++++----------------- README.md | 2 +- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/.github/sponsors/speakeasy-dark.svg b/.github/sponsors/speakeasy-dark.svg index bfcf4990e2..aae8f7a9d9 100644 --- a/.github/sponsors/speakeasy-dark.svg +++ b/.github/sponsors/speakeasy-dark.svg @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - + + + + + + + - + + + + + + + + + - - + + diff --git a/.github/sponsors/speakeasy-light.svg b/.github/sponsors/speakeasy-light.svg index 59ec648f4a..ab439943db 100644 --- a/.github/sponsors/speakeasy-light.svg +++ b/.github/sponsors/speakeasy-light.svg @@ -1,23 +1,15 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 564d39f903..ea6887112f 100644 --- a/README.md +++ b/README.md @@ -4505,7 +4505,7 @@ In addition, we are also generously sponsored by the following folks, each of wh - Speakeasy logo + Speakeasy logo

From 562606929e705e99677f9f5d47fe33381b7462f4 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 20 Aug 2025 10:20:32 +0100 Subject: [PATCH 119/293] fix(deps): update module golang.org/x/tools to v0.25.1 As noted in https://github.com/golang/go/issues/74462, this is a required bump needed to allow building Go 1.25 on older versions of Go. --- examples/authenticated-api/stdhttp/go.mod | 5 +++-- examples/authenticated-api/stdhttp/go.sum | 16 +++++++-------- examples/extensions/xomitzero/go.mod | 5 +++-- examples/extensions/xomitzero/go.sum | 16 +++++++-------- examples/go.mod | 11 +++++----- examples/go.sum | 20 +++++++++---------- .../minimal-server/stdhttp-go-tool/go.mod | 5 +++-- .../minimal-server/stdhttp-go-tool/go.sum | 16 +++++++-------- examples/minimal-server/stdhttp/go.mod | 5 +++-- examples/minimal-server/stdhttp/go.sum | 16 +++++++-------- .../go.mod | 5 +++-- .../go.sum | 16 +++++++-------- examples/petstore-expanded/stdhttp/go.mod | 5 +++-- examples/petstore-expanded/stdhttp/go.sum | 16 +++++++-------- go.mod | 5 +++-- go.sum | 16 +++++++-------- internal/test/go.mod | 11 +++++----- internal/test/go.sum | 20 +++++++++---------- internal/test/strict-server/stdhttp/go.mod | 5 +++-- internal/test/strict-server/stdhttp/go.sum | 16 +++++++-------- 20 files changed, 120 insertions(+), 110 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 4a60a8451a..72bbc87410 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -38,9 +38,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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 index 712a223d85..fa3fc87236 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -135,8 +135,8 @@ golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -149,8 +149,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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/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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -178,8 +178,8 @@ 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/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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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= @@ -200,8 +200,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index 63a0603f14..3cd8989504 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -25,9 +25,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index d6b9515854..1145dfe546 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -93,8 +93,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -102,8 +102,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -123,8 +123,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -136,8 +136,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/go.mod b/examples/go.mod index b47de77c71..70e2872aec 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -107,13 +107,14 @@ require ( 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/crypto v0.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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 diff --git a/examples/go.sum b/examples/go.sum index 809bd7b603..0dad876010 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -321,8 +321,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -330,8 +330,8 @@ 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -345,8 +345,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -377,8 +377,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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= @@ -400,8 +400,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f 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.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 894abfa890..92215b63f8 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -21,9 +21,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index d6b9515854..1145dfe546 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -93,8 +93,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -102,8 +102,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -123,8 +123,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -136,8 +136,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index c7482feec2..98e2cc993c 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -20,9 +20,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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 index d6b9515854..1145dfe546 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -93,8 +93,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -102,8 +102,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -123,8 +123,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -136,8 +136,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod index d8ff6c8582..2cce45d636 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -25,9 +25,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum index d6b9515854..1145dfe546 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -93,8 +93,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -102,8 +102,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -123,8 +123,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -136,8 +136,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index c5621598c1..d7db39edfb 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -31,9 +31,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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 index dd7bd07c8b..1f33fd6378 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -110,8 +110,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -119,8 +119,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -140,8 +140,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -153,8 +153,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/go.mod b/go.mod index f7b97aa03d..e81754e990 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,9 @@ require ( github.com/getkin/kin-openapi v0.132.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.10.0 - golang.org/x/mod v0.17.0 + golang.org/x/mod v0.21.0 golang.org/x/text v0.20.0 - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + golang.org/x/tools v0.25.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -28,4 +28,5 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + golang.org/x/sync v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index d6b9515854..1145dfe546 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -102,8 +102,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -123,8 +123,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -136,8 +136,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index f9f65fd96c..cc3895e975 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -95,13 +95,14 @@ require ( 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/crypto v0.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index 5d3c0a7e6c..c06053cef7 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -298,12 +298,12 @@ golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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/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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -313,8 +313,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -343,8 +343,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -359,8 +359,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index d8f9e9d0fa..2562e94b74 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -32,9 +32,10 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.25.1 // 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 index 4aaab49fca..32642f34a2 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -106,8 +106,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -115,8 +115,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= @@ -136,8 +136,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -149,8 +149,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= +golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 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= From bdc4edce7476be0791dc670d695fd78378e0e9b6 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 13 Aug 2025 09:52:48 +0100 Subject: [PATCH 120/293] build: test against Go 1.25 --- .github/workflows/ci.yml | 1 + .github/workflows/generate.yml | 1 + .github/workflows/lint.yml | 1 + .github/workflows/tidy.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37560a65ba..21f6d75e5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: - "1.22" - "1.23" - "1.24" + - "1.25" steps: - name: Check out source code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 831d4c5888..828c265dea 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -12,6 +12,7 @@ jobs: - "1.22" - "1.23" - "1.24" + - "1.25" steps: - name: Check out source code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 423340111f..7d9d49b770 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,6 +12,7 @@ jobs: - "1.22" - "1.23" - "1.24" + - "1.25" steps: - name: Check out source code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index a09d6bf35f..9e43e22722 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -12,6 +12,7 @@ jobs: - "1.22" - "1.23" - "1.24" + - "1.25" steps: - name: Check out source code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 From 3eff0a25e492a714ea0b2d8508c59fd898881fd0 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 10 Sep 2025 20:52:31 +0100 Subject: [PATCH 121/293] build: capture `govulncheck` results as Code Scanning alerts Related to [0] and regular questions we've had in the past, we don't have a clear answer for "are we vulnerable to a CVE" in a way that our users are clearly able to determine, as well as "will oapi-codegen fix it". As a step towards answering the former, and leading towards the latter, we can start running `govulncheck` in CI as a way to ensure that we always have that information to hand. This will re-run on commits to HEAD, as well as on a schedule, to make sure we're aware of new CVEs. By producing this in SARIF format, we can then have this uploaded to GitHub's Code Scanning alerts, which are more straightforward to validate. The Code Scanning alerts page is gated to maintainers, but doesn't (currently) hide anything that can't be seen by someone running `govulncheck` themselves on the project. We also make sure to explicitly note what permissions are required to handle the workflow. [0]: https://github.com/oapi-codegen/governance/issues/11 --- .github/workflows/govulncheck.yml | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/govulncheck.yml diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml new file mode 100644 index 0000000000..e2a5c05438 --- /dev/null +++ b/.github/workflows/govulncheck.yml @@ -0,0 +1,35 @@ +name: Determine known CVEs through `govulncheck` +on: + push: + branches: + - main + schedule: + # Mondays at 0000 + - cron: "0 0 * * 1" +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@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.2 + 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" From 20726e2848ea7d7abc89e447d0d4ad92f2d9fd28 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 24 Sep 2025 16:04:32 +0100 Subject: [PATCH 122/293] docs: correct level of headers --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea6887112f..06bcf667ba 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest ## Install -## For Go 1.24+ +### For Go 1.24+ 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. @@ -59,7 +59,7 @@ From there, each invocation of `oapi-codegen` would be used like so: //go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml ``` -## Prior to Go 1.24 +### Prior to Go 1.24 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. From 72d2e08ca69d3a664c4f951195a7e317f756b8db Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 24 Sep 2025 20:10:24 +0100 Subject: [PATCH 123/293] docs: clarify support + `go` directives This is a first version to clarify the current state of things, and answer a few common questions. --- SUPPORT.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SUPPORT.md 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). From d39bf2d10743acc211b8c15a278209501e94fff1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Wed, 24 Sep 2025 18:10:30 +0100 Subject: [PATCH 124/293] build: add Scorecards workflow This is another step towards better understanding this project's health, and making it clear to consumers. Although we're already onboarded via the upstream project[0] (via the "old" repo name), it's better to have this a first-class product of our project, as this also allows validating i.e. branch protection due to `permissions: read-all`. Takes configuration via Renovate's usage[1], alongside the suggested version from the Scorecard project. This uploads the SARIF results to show that we have issues in the Security tab (for maintainers). [0]: https://securityscorecards.dev/viewer/?uri=github.com%2Fdeepmap%2Foapi-codegen [1]: https://github.com/renovatebot/renovate/blob/8b86b8cdb4a3e36d6211e47a2e6a201f25f674da/.github/workflows/scorecard.yml --- .github/workflows/scorecard.yml | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..493707388e --- /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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + show-progress: false + + - name: "Run analysis" + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: "Upload artifact" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + 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@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + with: + sarif_file: results.sarif From e98114a095ff656d6c4007c643de95e28285be74 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 25 Sep 2025 17:51:43 +0100 Subject: [PATCH 125/293] build: add explicit `permissions` blocks for Actions This mirrors what we have set at a repo- and org-level as defaults (`Read repository contents and packages permissions`), but this makes it explicit for Static Analysis tools. --- .github/workflows/ci.yml | 4 ++++ .github/workflows/generate.yml | 4 ++++ .github/workflows/govulncheck.yml | 4 ++++ .github/workflows/labeler.yml | 3 +++ .github/workflows/lint.yml | 4 ++++ 5 files changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 21f6d75e5f..d79e596cf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,9 @@ name: Build project on: [ push, pull_request ] + +permissions: + contents: read + jobs: build: name: Build diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 828c265dea..3ceb479fcc 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -1,5 +1,9 @@ name: Ensure generated files are up-to-date on: [ push, pull_request ] + +permissions: + contents: read + jobs: build: name: Build diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index e2a5c05438..51ef2084e5 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -6,6 +6,10 @@ on: schedule: # Mondays at 0000 - cron: "0 0 * * 1" + +permissions: + contents: read + jobs: check-for-vulnerabilities: name: Check for vulnerabilities using `govulncheck` diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index b1cdfcf47d..a304cedcab 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -2,6 +2,9 @@ name: "Pull Request Labeler" on: - pull_request_target +permissions: + contents: read + jobs: labeler: permissions: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7d9d49b770..ad9ec3b3d4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,5 +1,9 @@ name: Lint project on: [push, pull_request] + +permissions: + contents: read + jobs: build: name: Build From 0d94f2f2015e5fec2cd66273eeb8eff7d1f86bc1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 25 Sep 2025 17:47:42 +0100 Subject: [PATCH 126/293] build: add explicit `permissions` blocks for `tidy.yml` Missed from e98114a095ff656d6c4007c643de95e28285be74. --- .github/workflows/tidy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 9e43e22722..fadd9d3ecf 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -1,5 +1,9 @@ name: Ensure `go mod tidy` has been run on: [ push, pull_request ] + +permissions: + contents: read + jobs: build: name: Build From 7a6b40a2c9ac5a5f6b4c66b3229bb84276358010 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 10:54:41 +0000 Subject: [PATCH 127/293] fix: report formatting errors with line numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When formatting the resulting output, using `goimports`, we may receive an error due to generating invalid code using our templates. The output returned is fairly unhelpful, noting a line number, but requiring the users to take the broken output and then paste it into something that has a line number. This improves the output by reporting: - line numbers for the resulting Go code - a ❗ where the (first) formatting error is found --- pkg/codegen/codegen.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 6e602ea05a..04ac96cc66 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -19,7 +19,9 @@ import ( "bytes" "context" "embed" + "errors" "fmt" + "go/scanner" "io" "io/fs" "net/http" @@ -435,11 +437,36 @@ 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) + // if we don't get a line number + errLine := -1 + var scanErr scanner.ErrorList + if errors.As(err, &scanErr) && scanErr.Len() > 0 { + // for now, only return the first error's information + errLine = scanErr[0].Pos.Line + } + return "", fmt.Errorf("error formatting Go code:\n%s\nerror was: %w", addLineNumbers(goCode, errLine), err) } return string(outBytes), nil } +func addLineNumbers(goCode string, lineWithError int) string { + var out []string + lines := strings.Split(goCode, "\n") + for i, line := range lines { + // lines for humans start at 1 + lineNumber := i + 1 + + errLine := " " + if lineNumber == lineWithError { + errLine = "❗" + } + + out = append(out, fmt.Sprintf("%s%5d: %s", errLine, lineNumber, line)) + } + + return strings.Join(out, "\n") +} + func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []OperationDefinition, excludeSchemas []string) (string, error) { var allTypes []TypeDefinition if swagger.Components != nil { From 15c2a0a6aa74f56e2f42e0a6fd7987967ec3364d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 11:46:26 +0000 Subject: [PATCH 128/293] build: handle additional values in `GOVERSION` When building locally, the `make` scripts are failing on the result of: ``` $ go env GOVERSION go1.25.3 X:nodwarf5 ``` This splits the input correctly. --- examples/authenticated-api/stdhttp/Makefile | 2 +- examples/extensions/xomitzero/Makefile | 2 +- examples/minimal-server/stdhttp-go-tool/Makefile | 2 +- examples/minimal-server/stdhttp/Makefile | 2 +- .../preferskipoptionalpointerwithomitzero/Makefile | 2 +- examples/petstore-expanded/stdhttp/Makefile | 2 +- internal/test/strict-server/stdhttp/Makefile | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/authenticated-api/stdhttp/Makefile b/examples/authenticated-api/stdhttp/Makefile index 7173d70211..48fe768e30 100644 --- a/examples/authenticated-api/stdhttp/Makefile +++ b/examples/authenticated-api/stdhttp/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-122 @{ \ diff --git a/examples/extensions/xomitzero/Makefile b/examples/extensions/xomitzero/Makefile index e99db23781..bb37d63394 100644 --- a/examples/extensions/xomitzero/Makefile +++ b/examples/extensions/xomitzero/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-124 @{ \ diff --git a/examples/minimal-server/stdhttp-go-tool/Makefile b/examples/minimal-server/stdhttp-go-tool/Makefile index e99db23781..bb37d63394 100644 --- a/examples/minimal-server/stdhttp-go-tool/Makefile +++ b/examples/minimal-server/stdhttp-go-tool/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-124 @{ \ diff --git a/examples/minimal-server/stdhttp/Makefile b/examples/minimal-server/stdhttp/Makefile index 7173d70211..48fe768e30 100644 --- a/examples/minimal-server/stdhttp/Makefile +++ b/examples/minimal-server/stdhttp/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-122 @{ \ diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile b/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile index e99db23781..bb37d63394 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-124 @{ \ diff --git a/examples/petstore-expanded/stdhttp/Makefile b/examples/petstore-expanded/stdhttp/Makefile index 7173d70211..48fe768e30 100644 --- a/examples/petstore-expanded/stdhttp/Makefile +++ b/examples/petstore-expanded/stdhttp/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-122 @{ \ diff --git a/internal/test/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile index 7173d70211..48fe768e30 100644 --- a/internal/test/strict-server/stdhttp/Makefile +++ b/internal/test/strict-server/stdhttp/Makefile @@ -4,7 +4,7 @@ YELLOW := \e[0;33m RESET := \e[0;0m GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)") +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") define execute-if-go-122 @{ \ From 9e4987a0058882027da59a851abadf9873860b37 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 10:59:30 +0000 Subject: [PATCH 129/293] chore(templates): add `Property.ZeroValueIsNil` helper method As part of #2031, we need to correct a subtle breakage in #1981, where we would not correctly perform the nil check on arrays, breaking marshalling functionality. As a first step, we add a new helper method to inform as to whether the zero value of a Property could be `nil`, and therefore needs a `nil` check. --- pkg/codegen/schema.go | 11 +++++++ pkg/codegen/schema_test.go | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 1d03fbdd0e..8b9b38a0e8 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -134,6 +134,17 @@ func (p Property) HasOptionalPointer() bool { return p.Required == false && p.Schema.SkipOptionalPointer == false //nolint:staticcheck } +// ZeroValueIsNil is a helper function to determine if the given Go type used for this property +// Will return true if the OpenAPI `type` is: +// - `array` +func (p Property) ZeroValueIsNil() bool { + if p.Schema.OAPISchema == nil { + return false + } + + return p.Schema.OAPISchema.Type.Is("array") +} + // 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 diff --git a/pkg/codegen/schema_test.go b/pkg/codegen/schema_test.go index c4b3f8bd7b..6075594a32 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,66 @@ 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 + 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 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, + }, + } + if tt.expectIsNil { + require.True(t, prop.ZeroValueIsNil()) + } else { + require.False(t, prop.ZeroValueIsNil()) + } + }) + } +} From 0f080c88bdc68b0ea4cc9a9a393b7c3d44894f1f Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 11:10:10 +0000 Subject: [PATCH 130/293] chore(templates): add `Property.RequiresPointerCheck` helper method As part of #2031, we need to correct a subtle breakage in #1981, where we would not correctly perform the nil check on arrays, breaking marshalling functionality. As a first step, we add a new helper method to be used to validate whether a `nil` check is required on a given type, which is used for either types with a zero value of `nil`, or where we have an optional pointer set. --- pkg/codegen/schema.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 8b9b38a0e8..c099752d88 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -128,6 +128,12 @@ 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 { From c4ba545dc7f4c67d796d7fbde1203b775f3a3056 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 10:17:27 +0000 Subject: [PATCH 131/293] fix(templates): correctly nil check arrays As part of #2031, we need to correct a subtle breakage in #1981, where we would not correctly perform the nil check on arrays, breaking marshalling functionality. To do this we can modify our templates to call the newly added `RequiresNilCheck` when performing nil checks Closes #2031. Co-authored-by: Matthew Gabeler-Lee --- internal/test/issues/issue-2031/config.yaml | 4 + internal/test/issues/issue-2031/generate.go | 3 + .../test/issues/issue-2031/issue2031.gen.go | 83 +++++++++++++++++++ .../test/issues/issue-2031/issue2031_test.go | 18 ++++ internal/test/issues/issue-2031/openapi.yaml | 27 ++++++ .../templates/additional-properties.tmpl | 4 +- .../union-and-additional-properties.tmpl | 4 +- pkg/codegen/templates/union.tmpl | 4 +- 8 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 internal/test/issues/issue-2031/config.yaml create mode 100644 internal/test/issues/issue-2031/generate.go create mode 100644 internal/test/issues/issue-2031/issue2031.gen.go create mode 100644 internal/test/issues/issue-2031/issue2031_test.go create mode 100644 internal/test/issues/issue-2031/openapi.yaml 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/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl index 2f450582d1..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 .HasOptionalPointer}}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 .HasOptionalPointer}} }{{end}} +{{if .RequiresNilCheck}} }{{end}} {{end}} for fieldName, field := range a.AdditionalProperties { object[fieldName], err = json.Marshal(field) diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl index 1c48092ccf..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 .HasOptionalPointer}}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 .HasOptionalPointer}} }{{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 c0385f82e3..b27a2aca3f 100644 --- a/pkg/codegen/templates/union.tmpl +++ b/pkg/codegen/templates/union.tmpl @@ -102,12 +102,12 @@ } } {{range .Schema.Properties}} - {{if .HasOptionalPointer}}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 .HasOptionalPointer}} }{{end}} + {{if .RequiresNilCheck}} }{{end}} {{end -}} b, err = json.Marshal(object) {{end -}} From 0ef233ff214ee41d06c2d41a5266b452573294f3 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 12:06:28 +0000 Subject: [PATCH 132/293] chore(renovate): group dependency updates by directory As we have a monorepo of dependencies, via [0] we can wrap updates into their own PRs, denoted by the directory the PR is for. [0]: https://www.jvt.me/posts/2025/07/07/renovate-monorepo/ --- renovate.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index cb5f9a2063..d5d222946e 100644 --- a/renovate.json +++ b/renovate.json @@ -5,5 +5,15 @@ ], "gomod": { "ignorePaths": [] - } + }, + "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 }}{{packageFileDir}}/{{/if}}", + "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{packageFileDir}}){{/if}}" + } + ] } From 066711630d24cdb4daaa262142d5164ced4d5077 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 12:08:23 +0000 Subject: [PATCH 133/293] chore(renovate): don't raise PRs for `internal/test` and `examples` As a way to limit the number of PRs to only "important" updates for the core project. However, we still want visibility through our Dependency Dashboard. --- renovate.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/renovate.json b/renovate.json index d5d222946e..a8e4b150fe 100644 --- a/renovate.json +++ b/renovate.json @@ -14,6 +14,14 @@ ], "additionalBranchPrefix": "{{#if isGroup }}{{ else }}{{packageFileDir}}/{{/if}}", "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{packageFileDir}}){{/if}}" + }, + { + "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 } ] } From 06a65c88955f86d4906058e3b463717bed67336c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 12:16:43 +0000 Subject: [PATCH 134/293] chore(renovate): don't raise PRs for internal `replace`d modules As we never want them to be non-`replace`'d. --- renovate.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/renovate.json b/renovate.json index a8e4b150fe..df8a3c23c9 100644 --- a/renovate.json +++ b/renovate.json @@ -22,6 +22,22 @@ "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 } ] } From 2618db7acdd47621bf767f8241e790ae5c48513e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:45:15 +0000 Subject: [PATCH 135/293] chore(deps): update github/codeql-action action to v4 (.github/workflows) --- .github/workflows/govulncheck.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 51ef2084e5..0e4f8a1451 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -29,7 +29,7 @@ jobs: # ... 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@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.2 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: sarif_file: govulncheck.sarif category: govulncheck diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 493707388e..67bed53763 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,6 +41,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: sarif_file: results.sarif From f6a603ac8123105f02ce8740520ee2f97f46f644 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:45:02 +0000 Subject: [PATCH 136/293] chore(deps): update actions/checkout action to v5 (.github/workflows) --- .github/workflows/ci.yml | 2 +- .github/workflows/generate.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tidy.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d79e596cf9..63fbeff131 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - "1.25" steps: - name: Check out source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 3ceb479fcc..b145336e72 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -19,7 +19,7 @@ jobs: - "1.25" steps: - name: Check out source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ad9ec3b3d4..959b6cf6f0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: - "1.25" steps: - name: Check out source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index fadd9d3ecf..2eb82679eb 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -19,7 +19,7 @@ jobs: - "1.25" steps: - name: Check out source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 From 78601a51433450570cc7c87b6dadce5b8d32aa80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:45:06 +0000 Subject: [PATCH 137/293] chore(deps): update actions/labeler action to v6 (.github/workflows) --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index a304cedcab..c7eb2865f1 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -12,4 +12,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5 + - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 From 67c6c89fa92f126e006a7e9007af9d28aabea230 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:45:10 +0000 Subject: [PATCH 138/293] chore(deps): update actions/setup-go action to v6 (.github/workflows) --- .github/workflows/ci.yml | 2 +- .github/workflows/generate.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tidy.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63fbeff131..eeb0208241 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index b145336e72..4a0e5db377 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 959b6cf6f0..8246442b1e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.version }} diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml index 2eb82679eb..4d5e66a992 100644 --- a/.github/workflows/tidy.yml +++ b/.github/workflows/tidy.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up Go - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ matrix.version }} From 1a6d918e3f39dc7a332c2f1b5e37f2c928f778b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:45:57 +0000 Subject: [PATCH 139/293] chore(deps): update actions/upload-artifact action to v5 (.github/workflows) --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 67bed53763..811dede88c 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif From ae106adb9f513769a5d91169b8bf44c170335aab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:39:54 +0000 Subject: [PATCH 140/293] chore(deps): update ossf/scorecard-action action to v2.4.3 (.github/workflows) --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 811dede88c..dcb2390b74 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -26,7 +26,7 @@ jobs: show-progress: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif From 226a25fae40c4595f950c883af1616b084ad45a0 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 1 Nov 2025 12:45:45 +0000 Subject: [PATCH 141/293] chore(renovate): correctly create branches for top-level files Previously, the `packageFileDir` would be set to "", so the branch name would be generated as: "branchName": "renovate//github.com-golangci-golangci-lint-2.x" With this fix, we see: "branchName": "renovate/Makefile/github.com-golangci-golangci-lint-2.x", Adding in the `packageFile` makes it clearer than "just" a `/` or an empty string. --- renovate.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/renovate.json b/renovate.json index df8a3c23c9..dac5dde8b9 100644 --- a/renovate.json +++ b/renovate.json @@ -12,8 +12,8 @@ "matchFileNames": [ "**/*" ], - "additionalBranchPrefix": "{{#if isGroup }}{{ else }}{{packageFileDir}}/{{/if}}", - "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{packageFileDir}}){{/if}}" + "additionalBranchPrefix": "{{#if isGroup }}{{ else }}{{#if packageFileDir}}{{packageFileDir}}/{{else}}{{packageFile}}/{{/if}}{{/if}}", + "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{#if packageFileDir}}{{packageFileDir}}{{else}}{{packageFile}}{{/if}}){{/if}}" }, { "description": "Don't attempt to bump dependencies if they're only used in example code, but allow manually forcing them via Dependency Dashboard", From f7a23df40130ae1b4a72fdceb04973cffda770eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:06:29 +0000 Subject: [PATCH 142/293] chore(deps): update module github.com/golangci/golangci-lint to v2.6.0 (makefile) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 777160b716..069527cf0e 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) v2.2.2 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v2.6.0 .PHONY: tools tools: $(GOBIN)/golangci-lint From 029a7399b71dea5d555f38f9c604bb0c703fd1e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:11:37 +0000 Subject: [PATCH 143/293] fix(deps): update module github.com/stretchr/testify to v1.11.1 (go.mod) --- examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 4 ++-- examples/extensions/xomitzero/go.mod | 2 +- examples/extensions/xomitzero/go.sum | 4 ++-- examples/go.mod | 2 +- examples/go.sum | 4 ++-- examples/minimal-server/stdhttp-go-tool/go.sum | 4 ++-- examples/minimal-server/stdhttp/go.sum | 4 ++-- .../preferskipoptionalpointerwithomitzero/go.mod | 2 +- .../preferskipoptionalpointerwithomitzero/go.sum | 4 ++-- examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 ++-- 18 files changed, 28 insertions(+), 28 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 72bbc87410..368fdc37cb 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( 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.10.0 + github.com/stretchr/testify v1.11.1 ) require ( diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index fa3fc87236..fc30aa1c2a 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -116,8 +116,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index 3cd8989504..f45afe8b24 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -6,7 +6,7 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 ) require ( diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index 1145dfe546..adcfa0dd30 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -82,8 +82,8 @@ github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qY 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/go.mod b/examples/go.mod index 70e2872aec..f9159ae825 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,7 +22,7 @@ require ( 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.10.0 + github.com/stretchr/testify v1.11.1 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 ) diff --git a/examples/go.sum b/examples/go.sum index 0dad876010..dd5d8bd2b2 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -270,8 +270,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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.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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index 1145dfe546..adcfa0dd30 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -82,8 +82,8 @@ github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qY 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index 1145dfe546..adcfa0dd30 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -82,8 +82,8 @@ github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qY 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod index 2cce45d636..a0deac3c68 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -6,7 +6,7 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 ) require ( diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum index 1145dfe546..adcfa0dd30 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -82,8 +82,8 @@ github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qY 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index d7db39edfb..3447ca1442 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( 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.10.0 + github.com/stretchr/testify v1.11.1 ) require ( diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 1f33fd6378..c52748b6f7 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -99,8 +99,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/go.mod b/go.mod index e81754e990..c454d95057 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.5 require ( github.com/getkin/kin-openapi v0.132.0 github.com/speakeasy-api/openapi-overlay v0.10.2 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 golang.org/x/mod v0.21.0 golang.org/x/text v0.20.0 golang.org/x/tools v0.25.1 diff --git a/go.sum b/go.sum index 1145dfe546..adcfa0dd30 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qY 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/internal/test/go.mod b/internal/test/go.mod index cc3895e975..703768eeec 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -17,7 +17,7 @@ require ( 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.10.0 + github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/internal/test/go.sum b/internal/test/go.sum index c06053cef7..ff0404cfe0 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -249,8 +249,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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.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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 2562e94b74..820cd305b9 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -12,7 +12,7 @@ require ( 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.10.0 + github.com/stretchr/testify v1.11.1 ) require ( diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 32642f34a2..7f1a13fd03 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -95,8 +95,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= From 1401fbe26ce7e128e9963786742490ff444e3795 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:11:31 +0000 Subject: [PATCH 144/293] fix(deps): update module github.com/getkin/kin-openapi to v0.133.0 (go.mod) --- examples/authenticated-api/stdhttp/go.mod | 3 ++- examples/authenticated-api/stdhttp/go.sum | 6 ++++-- examples/extensions/xomitzero/go.mod | 3 ++- examples/extensions/xomitzero/go.sum | 6 ++++-- examples/go.mod | 3 ++- examples/go.sum | 6 ++++-- examples/minimal-server/stdhttp-go-tool/go.mod | 3 ++- examples/minimal-server/stdhttp-go-tool/go.sum | 6 ++++-- examples/minimal-server/stdhttp/go.mod | 3 ++- examples/minimal-server/stdhttp/go.sum | 6 ++++-- .../preferskipoptionalpointerwithomitzero/go.mod | 3 ++- .../preferskipoptionalpointerwithomitzero/go.sum | 6 ++++-- examples/petstore-expanded/stdhttp/go.mod | 3 ++- examples/petstore-expanded/stdhttp/go.sum | 6 ++++-- go.mod | 3 ++- go.sum | 6 ++++-- internal/test/go.mod | 3 ++- internal/test/go.sum | 6 ++++-- internal/test/strict-server/stdhttp/go.mod | 3 ++- internal/test/strict-server/stdhttp/go.sum | 6 ++++-- 20 files changed, 60 insertions(+), 30 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 368fdc37cb..2ca2945993 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.132.0 + github.com/getkin/kin-openapi v0.133.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 @@ -37,6 +37,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index fc30aa1c2a..d38b743f8d 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -122,6 +122,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index f45afe8b24..e7b7295e3e 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -12,7 +12,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -25,6 +25,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index adcfa0dd30..2319ae885e 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -88,6 +88,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/examples/go.mod b/examples/go.mod index f9159ae825..7c9b783567 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.132.0 + github.com/getkin/kin-openapi v0.133.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 @@ -105,6 +105,7 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.27.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index dd5d8bd2b2..97e7e8ae43 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -52,8 +52,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -296,6 +296,8 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 92215b63f8..7c900939fb 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -8,7 +8,7 @@ tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -21,6 +21,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp-go-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index adcfa0dd30..2319ae885e 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -88,6 +88,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 98e2cc993c..9661c9998f 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -8,7 +8,7 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -20,6 +20,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index adcfa0dd30..2319ae885e 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -88,6 +88,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod index a0deac3c68..f3b0a6cfe8 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -12,7 +12,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -25,6 +25,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum index adcfa0dd30..2319ae885e 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -88,6 +88,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 3447ca1442..c1ef1e0491 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.132.0 + github.com/getkin/kin-openapi v0.133.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 @@ -31,6 +31,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index c52748b6f7..458fbf7291 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -105,6 +105,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/go.mod b/go.mod index c454d95057..9431a8d978 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.22.5 require ( - github.com/getkin/kin-openapi v0.132.0 + github.com/getkin/kin-openapi v0.133.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.11.1 golang.org/x/mod v0.21.0 @@ -28,5 +28,6 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/sync v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index adcfa0dd30..2319ae885e 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -88,6 +88,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 703768eeec..10ef9b25ed 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.132.0 + github.com/getkin/kin-openapi v0.133.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 @@ -93,6 +93,7 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.27.0 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index ff0404cfe0..ca696cc621 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -51,8 +51,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -276,6 +276,8 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= 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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 820cd305b9..5d3c8860d2 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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.132.0 + github.com/getkin/kin-openapi v0.133.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 @@ -32,6 +32,7 @@ require ( github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 7f1a13fd03..7fe4b88d07 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -14,8 +14,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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= @@ -101,6 +101,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= From 998bf1cfac5e0968d57397a389a4be6d59d65f8d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 9 Sep 2025 16:38:03 +0100 Subject: [PATCH 145/293] docs(sponsors): remove Elastic as a sponsor As I no longer work there, I'm no longer benefiting from the 4hr/month benefits that I had in the past. Conversations are still ongoing internally as to whether they'll become a 1hr/month sponsor. --- .github/sponsors/elastic-dark.svg | 23 ----------------------- .github/sponsors/elastic-light.svg | 23 ----------------------- README.md | 12 ------------ 3 files changed, 58 deletions(-) delete mode 100644 .github/sponsors/elastic-dark.svg delete mode 100644 .github/sponsors/elastic-light.svg diff --git a/.github/sponsors/elastic-dark.svg b/.github/sponsors/elastic-dark.svg deleted file mode 100644 index e12cc6c6ea..0000000000 --- a/.github/sponsors/elastic-dark.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.github/sponsors/elastic-light.svg b/.github/sponsors/elastic-light.svg deleted file mode 100644 index bdd2844636..0000000000 --- a/.github/sponsors/elastic-light.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index 06bcf667ba..9cb70c7c3d 100644 --- a/README.md +++ b/README.md @@ -4476,18 +4476,6 @@ Please consider sponsoring us through GitHub Sponsors either [on the organisatio 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 sponsored for 4 hours of work a month by Elastic: - -

- - - - - Elastic logo - - -

- In addition, we are also generously sponsored by the following folks, each of whom provide sponsorship for 1 hour of work a month:

From 5198fe7fe41d3f202a9c8c876ddc494b48122946 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:11:22 +0000 Subject: [PATCH 146/293] chore(deps): update release-drafter/release-drafter action to v6.1.0 (.github/workflows) --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index b71effb618..5f2ab3f3cd 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@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6 + - uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0 with: name: next tag: next From 89f7d4d16ec19ea42d64ace4d40d7102f241d66c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 3 Nov 2025 13:30:39 +0000 Subject: [PATCH 147/293] chore(renovate): run `make tidy` after dependency updates to `go.mod` As we've had it allowlisted by Mend, we can now run `make tidy` to get PRs automagically updated. This will update the whole branch (in the case of multiple dependency bumps on the branch) and only target Go-specific dependency changes, avoiding unnecessary updates when doing i.e. `golangci-lint` updates. --- renovate.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index dac5dde8b9..5627a8ac51 100644 --- a/renovate.json +++ b/renovate.json @@ -39,5 +39,15 @@ "matchCurrentVersion": "v0.0.0-00010101000000-000000000000", "enabled": false } - ] + ], + "postUpgradeTasks": { + "commands": [ + "make tidy" + ], + "fileFilters": [ + "**/*/go.mod", + "**/*/go.sum" + ], + "executionMode": "branch" + } } From 09919e799e66ac51f797becb8bc4b130c6d5fa08 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 16 Nov 2025 17:49:20 +0000 Subject: [PATCH 148/293] fix(renovate): only run `make tidy` after Go module updates Otherwise we see i.e. ``` Command failed: make tidy make: go: No such file or directory make: *** [Makefile:44: tidy] Error 127 ``` --- renovate.json | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/renovate.json b/renovate.json index 5627a8ac51..85610cfaa1 100644 --- a/renovate.json +++ b/renovate.json @@ -38,16 +38,23 @@ ], "matchCurrentVersion": "v0.0.0-00010101000000-000000000000", "enabled": false + }, + { + "description": "", + "matchFileNames": [ + "**/*/go.mod", + "**/*.go.sum" + ], + "postUpgradeTasks": { + "commands": [ + "make tidy" + ], + "fileFilters": [ + "**/*/go.mod", + "**/*/go.sum" + ], + "executionMode": "branch" + } } - ], - "postUpgradeTasks": { - "commands": [ - "make tidy" - ], - "fileFilters": [ - "**/*/go.mod", - "**/*/go.sum" - ], - "executionMode": "branch" - } + ] } From 5206145c6c6fec742fcdb10d3caa2042a95baf2d Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 6 Feb 2026 17:04:08 -0800 Subject: [PATCH 149/293] OpenAPI v3.1 support, experimental re-implementation using libopenapi (#2197) This is a prototype implementation of a future versions of oapi-codegen. It's almost a full rewrite, heavily inspired by previous code, and lessons learned. - much more flexibility in configuring generated code - move from kin-openapi to libopenapi to support 3.1 and 3.2 specs - webhook support - callback support - incompatible codegen changes to aggregate types (allOf, anyOf, oneOf) - many existing codegen bugs around schemas fixed --- Makefile | 12 +- README.md | 4 +- experimental/Configuration.md | 246 ++ experimental/Makefile | 35 + experimental/README.md | 164 ++ experimental/cmd/oapi-codegen/main.go | 105 + experimental/examples/callback/client/main.go | 144 ++ experimental/examples/callback/config.yaml | 6 + experimental/examples/callback/doc.go | 13 + experimental/examples/callback/server/main.go | 116 + experimental/examples/callback/tree-farm.yaml | 138 ++ .../examples/callback/treefarm.gen.go | 503 ++++ .../examples/petstore-expanded/chi/Makefile | 35 + .../examples/petstore-expanded/chi/go.mod | 11 + .../examples/petstore-expanded/chi/go.sum | 4 + .../examples/petstore-expanded/chi/main.go | 40 + .../petstore-expanded/chi/server/petstore.go | 135 ++ .../chi/server/server.config.yaml | 6 + .../chi/server/server.gen.go | 1039 ++++++++ .../client/client.config.yaml | 8 + .../petstore-expanded/client/client.gen.go | 1225 ++++++++++ .../petstore-expanded/client/client_test.go | 161 ++ .../client/validator/main.go | 143 ++ .../examples/petstore-expanded/doc.go | 2 + .../petstore-expanded/echo-v4/Makefile | 35 + .../examples/petstore-expanded/echo-v4/go.mod | 23 + .../examples/petstore-expanded/echo-v4/go.sum | 33 + .../petstore-expanded/echo-v4/main.go | 34 + .../echo-v4/server/petstore.go | 123 + .../echo-v4/server/server.config.yaml | 6 + .../echo-v4/server/server.gen.go | 976 ++++++++ .../examples/petstore-expanded/echo/Makefile | 35 + .../examples/petstore-expanded/echo/go.mod | 11 + .../examples/petstore-expanded/echo/go.sum | 16 + .../examples/petstore-expanded/echo/main.go | 34 + .../petstore-expanded/echo/server/petstore.go | 123 + .../echo/server/server.config.yaml | 6 + .../echo/server/server.gen.go | 977 ++++++++ .../examples/petstore-expanded/fiber/Makefile | 35 + .../examples/petstore-expanded/fiber/go.mod | 31 + .../examples/petstore-expanded/fiber/go.sum | 51 + .../examples/petstore-expanded/fiber/main.go | 35 + .../fiber/server/petstore.go | 122 + .../fiber/server/server.config.yaml | 6 + .../fiber/server/server.gen.go | 969 ++++++++ .../examples/petstore-expanded/generate.go | 11 + .../examples/petstore-expanded/gin/Makefile | 35 + .../examples/petstore-expanded/gin/go.mod | 40 + .../examples/petstore-expanded/gin/go.sum | 92 + .../examples/petstore-expanded/gin/main.go | 40 + .../petstore-expanded/gin/server/petstore.go | 126 + .../gin/server/server.config.yaml | 6 + .../gin/server/server.gen.go | 1007 ++++++++ .../petstore-expanded/gorilla/Makefile | 35 + .../examples/petstore-expanded/gorilla/go.mod | 11 + .../examples/petstore-expanded/gorilla/go.sum | 4 + .../petstore-expanded/gorilla/main.go | 40 + .../gorilla/server/petstore.go | 135 ++ .../gorilla/server/server.config.yaml | 6 + .../gorilla/server/server.gen.go | 1035 ++++++++ .../examples/petstore-expanded/iris/Makefile | 35 + .../examples/petstore-expanded/iris/go.mod | 55 + .../examples/petstore-expanded/iris/go.sum | 178 ++ .../examples/petstore-expanded/iris/main.go | 35 + .../petstore-expanded/iris/server/petstore.go | 130 + .../iris/server/server.config.yaml | 6 + .../iris/server/server.gen.go | 973 ++++++++ .../petstore-expanded/models.config.yaml | 2 + .../petstore-expanded/petstore-expanded.yaml | 164 ++ .../petstore-expanded/petstore.gen.go | 117 + .../petstore-expanded/stdhttp/Makefile | 35 + .../examples/petstore-expanded/stdhttp/go.mod | 7 + .../examples/petstore-expanded/stdhttp/go.sum | 2 + .../petstore-expanded/stdhttp/main.go | 39 + .../stdhttp/server/petstore.go | 163 ++ .../stdhttp/server/server.config.yaml | 7 + .../stdhttp/server/server.gen.go | 1009 ++++++++ experimental/examples/webhook/client/main.go | 150 ++ experimental/examples/webhook/config.yaml | 6 + experimental/examples/webhook/doc.go | 13 + .../examples/webhook/door-badge-reader.yaml | 139 ++ .../examples/webhook/doorbadge.gen.go | 1069 +++++++++ experimental/examples/webhook/server/main.go | 186 ++ experimental/go.mod | 27 + experimental/go.sum | 41 + experimental/internal/codegen/clientgen.go | 349 +++ .../internal/codegen/clientgen_test.go | 188 ++ experimental/internal/codegen/codegen.go | 1101 +++++++++ .../internal/codegen/configuration.go | 317 +++ .../internal/codegen/configuration_test.go | 152 ++ experimental/internal/codegen/extension.go | 337 +++ .../codegen/extension_integration_test.go | 201 ++ .../internal/codegen/extension_test.go | 180 ++ experimental/internal/codegen/gather.go | 621 +++++ .../internal/codegen/gather_operations.go | 864 +++++++ experimental/internal/codegen/identifiers.go | 125 + .../internal/codegen/identifiers_test.go | 129 + experimental/internal/codegen/initiatorgen.go | 216 ++ experimental/internal/codegen/inline.go | 92 + experimental/internal/codegen/inline_test.go | 139 ++ experimental/internal/codegen/namemangling.go | 420 ++++ .../internal/codegen/namemangling_test.go | 195 ++ experimental/internal/codegen/operation.go | 287 +++ experimental/internal/codegen/output.go | 764 ++++++ experimental/internal/codegen/paramgen.go | 178 ++ .../internal/codegen/paramgen_test.go | 161 ++ experimental/internal/codegen/receivergen.go | 131 + experimental/internal/codegen/schema.go | 117 + experimental/internal/codegen/schemanames.go | 812 +++++++ experimental/internal/codegen/servergen.go | 180 ++ .../codegen/skip_external_ref_test.go | 68 + experimental/internal/codegen/structtags.go | 172 ++ .../internal/codegen/templates/embed.go | 9 + .../templates/files/client/base.go.tmpl | 95 + .../templates/files/client/interface.go.tmpl | 17 + .../templates/files/client/methods.go.tmpl | 40 + .../files/client/request_builders.go.tmpl | 177 ++ .../templates/files/client/simple.go.tmpl | 121 + .../templates/files/initiator/base.go.tmpl | 73 + .../files/initiator/interface.go.tmpl | 17 + .../templates/files/initiator/methods.go.tmpl | 41 + .../files/initiator/request_builders.go.tmpl | 149 ++ .../templates/files/initiator/simple.go.tmpl | 121 + .../files/params/bind_deep_object.go.tmpl | 271 +++ .../templates/files/params/bind_form.go.tmpl | 38 + .../files/params/bind_form_explode.go.tmpl | 145 ++ .../templates/files/params/bind_label.go.tmpl | 46 + .../files/params/bind_label_explode.go.tmpl | 51 + .../files/params/bind_matrix.go.tmpl | 47 + .../files/params/bind_matrix_explode.go.tmpl | 65 + .../files/params/bind_pipe_delimited.go.tmpl | 33 + .../bind_pipe_delimited_explode.go.tmpl | 9 + .../files/params/bind_simple.go.tmpl | 38 + .../files/params/bind_simple_explode.go.tmpl | 38 + .../files/params/bind_space_delimited.go.tmpl | 33 + .../bind_space_delimited_explode.go.tmpl | 9 + .../templates/files/params/helpers.go.tmpl | 260 ++ .../files/params/style_deep_object.go.tmpl | 74 + .../templates/files/params/style_form.go.tmpl | 132 ++ .../files/params/style_form_explode.go.tmpl | 130 + .../files/params/style_label.go.tmpl | 129 + .../files/params/style_label_explode.go.tmpl | 129 + .../files/params/style_matrix.go.tmpl | 132 ++ .../files/params/style_matrix_explode.go.tmpl | 130 + .../files/params/style_pipe_delimited.go.tmpl | 66 + .../style_pipe_delimited_explode.go.tmpl | 66 + .../files/params/style_simple.go.tmpl | 158 ++ .../files/params/style_simple_explode.go.tmpl | 128 + .../params/style_space_delimited.go.tmpl | 66 + .../style_space_delimited_explode.go.tmpl | 66 + .../files/server/chi/handler.go.tmpl | 59 + .../files/server/chi/interface.go.tmpl | 24 + .../files/server/chi/receiver.go.tmpl | 95 + .../files/server/chi/wrapper.go.tmpl | 166 ++ .../files/server/echo-v4/handler.go.tmpl | 34 + .../files/server/echo-v4/interface.go.tmpl | 24 + .../files/server/echo-v4/receiver.go.tmpl | 72 + .../files/server/echo-v4/wrapper.go.tmpl | 134 ++ .../files/server/echo/handler.go.tmpl | 35 + .../files/server/echo/interface.go.tmpl | 24 + .../files/server/echo/receiver.go.tmpl | 72 + .../files/server/echo/wrapper.go.tmpl | 134 ++ .../templates/files/server/errors.go.tmpl | 79 + .../files/server/fiber/handler.go.tmpl | 31 + .../files/server/fiber/interface.go.tmpl | 24 + .../files/server/fiber/receiver.go.tmpl | 71 + .../files/server/fiber/wrapper.go.tmpl | 137 ++ .../files/server/gin/handler.go.tmpl | 37 + .../files/server/gin/interface.go.tmpl | 24 + .../files/server/gin/receiver.go.tmpl | 78 + .../files/server/gin/wrapper.go.tmpl | 161 ++ .../files/server/gorilla/handler.go.tmpl | 57 + .../files/server/gorilla/interface.go.tmpl | 24 + .../files/server/gorilla/receiver.go.tmpl | 95 + .../files/server/gorilla/wrapper.go.tmpl | 169 ++ .../files/server/iris/handler.go.tmpl | 28 + .../files/server/iris/interface.go.tmpl | 24 + .../files/server/iris/receiver.go.tmpl | 84 + .../files/server/iris/wrapper.go.tmpl | 160 ++ .../files/server/param_types.go.tmpl | 24 + .../files/server/stdhttp/handler.go.tmpl | 63 + .../files/server/stdhttp/interface.go.tmpl | 13 + .../files/server/stdhttp/receiver.go.tmpl | 108 + .../files/server/stdhttp/wrapper.go.tmpl | 166 ++ .../codegen/templates/files/types/date.tmpl | 38 + .../codegen/templates/files/types/email.tmpl | 43 + .../codegen/templates/files/types/file.tmpl | 64 + .../templates/files/types/nullable.tmpl | 104 + .../codegen/templates/files/types/uuid.tmpl | 3 + .../internal/codegen/templates/funcs.go | 151 ++ .../internal/codegen/templates/registry.go | 909 +++++++ .../codegen/templates/test/types/date.gen.go | 46 + .../codegen/templates/test/types/date_test.go | 65 + .../codegen/templates/test/types/email.gen.go | 52 + .../templates/test/types/email_test.go | 176 ++ .../codegen/templates/test/types/file.gen.go | 74 + .../codegen/templates/test/types/file_test.go | 54 + .../codegen/templates/test/types/generate.go | 3 + .../templates/test/types/gentypes/main.go | 109 + .../codegen/templates/test/types/uuid.gen.go | 10 + .../codegen/templates/test/types/uuid_test.go | 53 + .../codegen/test/comprehensive/doc.go | 3 + .../comprehensive/output/comprehensive.gen.go | 2098 +++++++++++++++++ .../test/default_values/default_values.yaml | 158 ++ .../output/default_values.gen.go | 514 ++++ .../output/default_values_test.go | 324 +++ .../codegen/test/external_ref/config.yaml | 5 + .../test/external_ref/external_ref_test.go | 62 + .../test/external_ref/packagea/config.yaml | 4 + .../test/external_ref/packagea/spec.gen.go | 22 + .../test/external_ref/packagea/spec.yaml | 14 + .../test/external_ref/packageb/config.yaml | 2 + .../test/external_ref/packageb/spec.gen.go | 14 + .../test/external_ref/packageb/spec.yaml | 12 + .../codegen/test/external_ref/spec.gen.go | 26 + .../codegen/test/external_ref/spec.yaml | 14 + .../codegen/test/files/comprehensive.yaml | 861 +++++++ .../codegen/test/issues/issue_1029/doc.go | 5 + .../issues/issue_1029/output/types.gen.go | 186 ++ .../issues/issue_1029/output/types_test.go | 89 + .../codegen/test/issues/issue_1029/spec.yaml | 29 + .../codegen/test/issues/issue_1039/doc.go | 5 + .../issues/issue_1039/output/types.gen.go | 291 +++ .../issues/issue_1039/output/types_test.go | 266 +++ .../codegen/test/issues/issue_1039/spec.yaml | 86 + .../codegen/test/issues/issue_1397/doc.go | 5 + .../issues/issue_1397/output/types.gen.go | 114 + .../issues/issue_1397/output/types_test.go | 81 + .../codegen/test/issues/issue_1397/spec.yaml | 57 + .../codegen/test/issues/issue_1429/doc.go | 5 + .../issues/issue_1429/output/types.gen.go | 149 ++ .../issues/issue_1429/output/types_test.go | 37 + .../codegen/test/issues/issue_1429/spec.yaml | 33 + .../codegen/test/issues/issue_1496/doc.go | 5 + .../issues/issue_1496/output/types.gen.go | 168 ++ .../issues/issue_1496/output/types_test.go | 41 + .../codegen/test/issues/issue_1496/spec.yaml | 40 + .../codegen/test/issues/issue_1710/doc.go | 5 + .../issues/issue_1710/output/types.gen.go | 212 ++ .../issues/issue_1710/output/types_test.go | 102 + .../codegen/test/issues/issue_1710/spec.yaml | 76 + .../codegen/test/issues/issue_193/doc.go | 5 + .../test/issues/issue_193/output/types.gen.go | 71 + .../issues/issue_193/output/types_test.go | 76 + .../codegen/test/issues/issue_193/spec.yaml | 27 + .../codegen/test/issues/issue_2102/doc.go | 5 + .../issues/issue_2102/output/types.gen.go | 82 + .../issues/issue_2102/output/types_test.go | 52 + .../codegen/test/issues/issue_2102/spec.yaml | 39 + .../codegen/test/issues/issue_312/doc.go | 6 + .../test/issues/issue_312/output/types.gen.go | 97 + .../issues/issue_312/output/types_test.go | 72 + .../codegen/test/issues/issue_312/spec.yaml | 86 + .../codegen/test/issues/issue_502/doc.go | 5 + .../test/issues/issue_502/output/types.gen.go | 228 ++ .../issues/issue_502/output/types_test.go | 107 + .../codegen/test/issues/issue_502/spec.yaml | 29 + .../codegen/test/issues/issue_52/doc.go | 5 + .../test/issues/issue_52/output/types.gen.go | 87 + .../test/issues/issue_52/output/types_test.go | 64 + .../codegen/test/issues/issue_52/spec.yaml | 41 + .../codegen/test/issues/issue_579/doc.go | 5 + .../test/issues/issue_579/output/types.gen.go | 110 + .../issues/issue_579/output/types_test.go | 64 + .../codegen/test/issues/issue_579/spec.yaml | 30 + .../codegen/test/issues/issue_697/doc.go | 5 + .../test/issues/issue_697/output/types.gen.go | 81 + .../issues/issue_697/output/types_test.go | 58 + .../codegen/test/issues/issue_697/spec.yaml | 27 + .../codegen/test/issues/issue_775/doc.go | 5 + .../test/issues/issue_775/output/types.gen.go | 86 + .../issues/issue_775/output/types_test.go | 37 + .../codegen/test/issues/issue_775/spec.yaml | 22 + .../codegen/test/issues/issue_832/doc.go | 5 + .../test/issues/issue_832/output/types.gen.go | 91 + .../issues/issue_832/output/types_test.go | 62 + .../codegen/test/issues/issue_832/spec.yaml | 45 + .../issue_head_digit_operation_id/doc.go | 5 + .../output/types.gen.go | 69 + .../output/types_test.go | 50 + .../issue_head_digit_operation_id/spec.yaml | 20 + .../issues/issue_illegal_enum_names/doc.go | 5 + .../output/types.gen.go | 80 + .../output/types_test.go | 51 + .../issues/issue_illegal_enum_names/spec.yaml | 37 + .../codegen/test/nested_aggregate/doc.go | 3 + .../nested_aggregate/nested_aggregate.yaml | 62 + .../output/nested_aggregate.gen.go | 400 ++++ .../output/nested_aggregate_test.go | 332 +++ experimental/internal/codegen/typegen.go | 918 ++++++++ experimental/internal/codegen/typemapping.go | 98 + experimental/internal/codegen/typenames.go | 1 + scripts/foreach-module.sh | 20 + 293 files changed, 41797 insertions(+), 7 deletions(-) create mode 100644 experimental/Configuration.md create mode 100644 experimental/Makefile create mode 100644 experimental/README.md create mode 100644 experimental/cmd/oapi-codegen/main.go create mode 100644 experimental/examples/callback/client/main.go create mode 100644 experimental/examples/callback/config.yaml create mode 100644 experimental/examples/callback/doc.go create mode 100644 experimental/examples/callback/server/main.go create mode 100644 experimental/examples/callback/tree-farm.yaml create mode 100644 experimental/examples/callback/treefarm.gen.go create mode 100644 experimental/examples/petstore-expanded/chi/Makefile create mode 100644 experimental/examples/petstore-expanded/chi/go.mod create mode 100644 experimental/examples/petstore-expanded/chi/go.sum create mode 100644 experimental/examples/petstore-expanded/chi/main.go create mode 100644 experimental/examples/petstore-expanded/chi/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/chi/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/chi/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/client/client.config.yaml create mode 100644 experimental/examples/petstore-expanded/client/client.gen.go create mode 100644 experimental/examples/petstore-expanded/client/client_test.go create mode 100644 experimental/examples/petstore-expanded/client/validator/main.go create mode 100644 experimental/examples/petstore-expanded/doc.go create mode 100644 experimental/examples/petstore-expanded/echo-v4/Makefile create mode 100644 experimental/examples/petstore-expanded/echo-v4/go.mod create mode 100644 experimental/examples/petstore-expanded/echo-v4/go.sum create mode 100644 experimental/examples/petstore-expanded/echo-v4/main.go create mode 100644 experimental/examples/petstore-expanded/echo-v4/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/echo-v4/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/echo/Makefile create mode 100644 experimental/examples/petstore-expanded/echo/go.mod create mode 100644 experimental/examples/petstore-expanded/echo/go.sum create mode 100644 experimental/examples/petstore-expanded/echo/main.go create mode 100644 experimental/examples/petstore-expanded/echo/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/echo/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/echo/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/fiber/Makefile create mode 100644 experimental/examples/petstore-expanded/fiber/go.mod create mode 100644 experimental/examples/petstore-expanded/fiber/go.sum create mode 100644 experimental/examples/petstore-expanded/fiber/main.go create mode 100644 experimental/examples/petstore-expanded/fiber/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/fiber/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/fiber/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/generate.go create mode 100644 experimental/examples/petstore-expanded/gin/Makefile create mode 100644 experimental/examples/petstore-expanded/gin/go.mod create mode 100644 experimental/examples/petstore-expanded/gin/go.sum create mode 100644 experimental/examples/petstore-expanded/gin/main.go create mode 100644 experimental/examples/petstore-expanded/gin/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/gin/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/gin/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/gorilla/Makefile create mode 100644 experimental/examples/petstore-expanded/gorilla/go.mod create mode 100644 experimental/examples/petstore-expanded/gorilla/go.sum create mode 100644 experimental/examples/petstore-expanded/gorilla/main.go create mode 100644 experimental/examples/petstore-expanded/gorilla/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/gorilla/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/gorilla/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/iris/Makefile create mode 100644 experimental/examples/petstore-expanded/iris/go.mod create mode 100644 experimental/examples/petstore-expanded/iris/go.sum create mode 100644 experimental/examples/petstore-expanded/iris/main.go create mode 100644 experimental/examples/petstore-expanded/iris/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/iris/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/iris/server/server.gen.go create mode 100644 experimental/examples/petstore-expanded/models.config.yaml create mode 100644 experimental/examples/petstore-expanded/petstore-expanded.yaml create mode 100644 experimental/examples/petstore-expanded/petstore.gen.go create mode 100644 experimental/examples/petstore-expanded/stdhttp/Makefile create mode 100644 experimental/examples/petstore-expanded/stdhttp/go.mod create mode 100644 experimental/examples/petstore-expanded/stdhttp/go.sum create mode 100644 experimental/examples/petstore-expanded/stdhttp/main.go create mode 100644 experimental/examples/petstore-expanded/stdhttp/server/petstore.go create mode 100644 experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml create mode 100644 experimental/examples/petstore-expanded/stdhttp/server/server.gen.go create mode 100644 experimental/examples/webhook/client/main.go create mode 100644 experimental/examples/webhook/config.yaml create mode 100644 experimental/examples/webhook/doc.go create mode 100644 experimental/examples/webhook/door-badge-reader.yaml create mode 100644 experimental/examples/webhook/doorbadge.gen.go create mode 100644 experimental/examples/webhook/server/main.go create mode 100644 experimental/go.mod create mode 100644 experimental/go.sum create mode 100644 experimental/internal/codegen/clientgen.go create mode 100644 experimental/internal/codegen/clientgen_test.go create mode 100644 experimental/internal/codegen/codegen.go create mode 100644 experimental/internal/codegen/configuration.go create mode 100644 experimental/internal/codegen/configuration_test.go create mode 100644 experimental/internal/codegen/extension.go create mode 100644 experimental/internal/codegen/extension_integration_test.go create mode 100644 experimental/internal/codegen/extension_test.go create mode 100644 experimental/internal/codegen/gather.go create mode 100644 experimental/internal/codegen/gather_operations.go create mode 100644 experimental/internal/codegen/identifiers.go create mode 100644 experimental/internal/codegen/identifiers_test.go create mode 100644 experimental/internal/codegen/initiatorgen.go create mode 100644 experimental/internal/codegen/inline.go create mode 100644 experimental/internal/codegen/inline_test.go create mode 100644 experimental/internal/codegen/namemangling.go create mode 100644 experimental/internal/codegen/namemangling_test.go create mode 100644 experimental/internal/codegen/operation.go create mode 100644 experimental/internal/codegen/output.go create mode 100644 experimental/internal/codegen/paramgen.go create mode 100644 experimental/internal/codegen/paramgen_test.go create mode 100644 experimental/internal/codegen/receivergen.go create mode 100644 experimental/internal/codegen/schema.go create mode 100644 experimental/internal/codegen/schemanames.go create mode 100644 experimental/internal/codegen/servergen.go create mode 100644 experimental/internal/codegen/skip_external_ref_test.go create mode 100644 experimental/internal/codegen/structtags.go create mode 100644 experimental/internal/codegen/templates/embed.go create mode 100644 experimental/internal/codegen/templates/files/client/base.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/client/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/client/methods.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/client/request_builders.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/client/simple.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/initiator/base.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/initiator/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/initiator/methods.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/initiator/simple.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_form.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_label.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/helpers.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_form.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_label.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_simple.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/errors.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/param_types.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl create mode 100644 experimental/internal/codegen/templates/files/types/date.tmpl create mode 100644 experimental/internal/codegen/templates/files/types/email.tmpl create mode 100644 experimental/internal/codegen/templates/files/types/file.tmpl create mode 100644 experimental/internal/codegen/templates/files/types/nullable.tmpl create mode 100644 experimental/internal/codegen/templates/files/types/uuid.tmpl create mode 100644 experimental/internal/codegen/templates/funcs.go create mode 100644 experimental/internal/codegen/templates/registry.go create mode 100644 experimental/internal/codegen/templates/test/types/date.gen.go create mode 100644 experimental/internal/codegen/templates/test/types/date_test.go create mode 100644 experimental/internal/codegen/templates/test/types/email.gen.go create mode 100644 experimental/internal/codegen/templates/test/types/email_test.go create mode 100644 experimental/internal/codegen/templates/test/types/file.gen.go create mode 100644 experimental/internal/codegen/templates/test/types/file_test.go create mode 100644 experimental/internal/codegen/templates/test/types/generate.go create mode 100644 experimental/internal/codegen/templates/test/types/gentypes/main.go create mode 100644 experimental/internal/codegen/templates/test/types/uuid.gen.go create mode 100644 experimental/internal/codegen/templates/test/types/uuid_test.go create mode 100644 experimental/internal/codegen/test/comprehensive/doc.go create mode 100644 experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go create mode 100644 experimental/internal/codegen/test/default_values/default_values.yaml create mode 100644 experimental/internal/codegen/test/default_values/output/default_values.gen.go create mode 100644 experimental/internal/codegen/test/default_values/output/default_values_test.go create mode 100644 experimental/internal/codegen/test/external_ref/config.yaml create mode 100644 experimental/internal/codegen/test/external_ref/external_ref_test.go create mode 100644 experimental/internal/codegen/test/external_ref/packagea/config.yaml create mode 100644 experimental/internal/codegen/test/external_ref/packagea/spec.gen.go create mode 100644 experimental/internal/codegen/test/external_ref/packagea/spec.yaml create mode 100644 experimental/internal/codegen/test/external_ref/packageb/config.yaml create mode 100644 experimental/internal/codegen/test/external_ref/packageb/spec.gen.go create mode 100644 experimental/internal/codegen/test/external_ref/packageb/spec.yaml create mode 100644 experimental/internal/codegen/test/external_ref/spec.gen.go create mode 100644 experimental/internal/codegen/test/external_ref/spec.yaml create mode 100644 experimental/internal/codegen/test/files/comprehensive.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1029/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1029/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1029/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1039/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1039/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1039/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1397/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1397/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1397/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1429/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1429/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1429/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1496/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1496/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1496/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_1710/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_1710/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_1710/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_193/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_193/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_193/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_193/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_2102/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_2102/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_2102/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_312/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_312/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_312/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_312/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_502/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_502/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_502/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_502/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_52/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_52/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_52/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_52/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_579/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_579/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_579/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_579/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_697/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_697/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_697/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_697/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_775/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_775/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_775/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_775/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_832/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_832/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_832/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_832/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml create mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go create mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go create mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go create mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml create mode 100644 experimental/internal/codegen/test/nested_aggregate/doc.go create mode 100644 experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml create mode 100644 experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go create mode 100644 experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go create mode 100644 experimental/internal/codegen/typegen.go create mode 100644 experimental/internal/codegen/typemapping.go create mode 100644 experimental/internal/codegen/typenames.go create mode 100755 scripts/foreach-module.sh diff --git a/Makefile b/Makefile index 069527cf0e..89b6de0f6d 100644 --- a/Makefile +++ b/Makefile @@ -19,34 +19,34 @@ lint: tools # run the root module explicitly, to prevent recursive calls by re-invoking `make ...` top-level $(GOBIN)/golangci-lint run ./... # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint lint-ci: tools # for the root module, explicitly run the step, to prevent recursive calls $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint-ci' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint-ci generate: # for the root module, explicitly run the step, to prevent recursive calls go generate ./... # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make generate' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh generate test: # for the root module, explicitly run the step, to prevent recursive calls go test -cover ./... # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make test' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh test tidy: # for the root module, explicitly run the step, to prevent recursive calls go mod tidy # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy tidy-ci: # for the root module, explicitly run the step, to prevent recursive calls tidied -verbose # then, for all child modules, use a module-managed `Makefile` - git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy-ci' + GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy-ci diff --git a/README.md b/README.md index 9cb70c7c3d..b5ed0c8b98 100644 --- a/README.md +++ b/README.md @@ -393,7 +393,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/oapi-codegen/oapi-codegen/issues/373) + - OpenAPI 3.1 support is in experimental form, as a complete rewrite using [libopenapi](https://github.com/pb33f/libopenapi). Please look in the + `./experimental` directory. This is potentially the future V3 of `oapi-codegen` and is functionally complete, just not deeply tested yet. Many OpenAPI 3.1 + features are supported, such as webhooks and callbacks. - 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)) diff --git a/experimental/Configuration.md b/experimental/Configuration.md new file mode 100644 index 0000000000..55f550e2f3 --- /dev/null +++ b/experimental/Configuration.md @@ -0,0 +1,246 @@ +# Configuration Reference + +`oapi-codegen` is configured using a YAML file. All sections are optional — you only need to include what you want to change from the defaults. + +Below is a fully annotated configuration file showing every option. + +```yaml +# The Go package name for generated code. +# Can also be set with -package flag. +package: myapi + +# Output file path. +# Can also be set with -output flag. +# Default: .gen.go +output: types.gen.go + +# Generation controls which parts of the code are generated. +generation: + # Server framework to generate code for. + # Supported: "std-http", "chi", "echo", "echo/v4", "gin", "gorilla", "fiber", "iris" + # Default: "" (no server code generated) + server: std-http + + # Generate an HTTP client that returns *http.Response. + # Default: false + client: true + + # Generate a SimpleClient wrapper with typed responses. + # Requires client: true. + # Default: false + simple-client: true + + # Use model types from an external package instead of generating them locally. + # When set, models are imported rather than generated. + # Default: not set (models are generated locally) + models-package: + path: github.com/org/project/models + alias: models # optional, defaults to last segment of path + +# Type mappings: OpenAPI type/format to Go type. +# User values are merged on top of defaults — you only need to specify overrides. +type-mapping: + integer: + default: + type: int # default + formats: + int32: + type: int32 # default + int64: + type: int64 # default + number: + default: + type: float32 # default + formats: + double: + type: float64 # default + boolean: + default: + type: bool # default + string: + default: + type: string # default + formats: + byte: + type: "[]byte" # default + date: + type: Date # default, custom template type + date-time: + type: time.Time # default + import: time + uuid: + type: UUID # default, custom template type + email: + type: Email # default, custom template type + binary: + type: File # default, custom template type + json: + type: json.RawMessage # default + import: encoding/json + # Add your own format mappings: + money: + type: decimal.Decimal + import: github.com/shopspring/decimal + +# Name mangling: controls how OpenAPI names become Go identifiers. +# User values are merged on top of defaults. +name-mangling: + # Prefix prepended when a name starts with a digit. + # Default: "N" (e.g., "123foo" becomes "N123foo") + numeric-prefix: "N" + + # Prefix prepended when a name conflicts with a Go keyword. + # Default: "" (uses keyword-suffix instead) + keyword-prefix: "" + + # Characters that mark word boundaries (next letter is capitalised). + # Default includes most punctuation: - # @ ! $ & = . + : ; _ ~ space ( ) { } [ ] | < > ? / \ + word-separators: "-#@!$&=.+:;_~ (){}[]|<>?/\\" + + # Words that should remain all-uppercase. + initialisms: + - ACL + - API + - ASCII + - CPU + - CSS + - DB + - DNS + - EOF + - GUID + - HTML + - HTTP + - HTTPS + - ID + - IP + - JSON + - QPS + - RAM + - RPC + - SLA + - SMTP + - SQL + - SSH + - TCP + - TLS + - TTL + - UDP + - UI + - UID + - GID + - URI + - URL + - UTF8 + - UUID + - VM + - XML + - XMPP + - XSRF + - XSS + - SIP + - RTP + - AMQP + - TS + + # Characters that get replaced with words when they appear at the start of a name. + character-substitutions: + "$": DollarSign + "-": Minus + "+": Plus + "&": And + "|": Or + "~": Tilde + "=": Equal + ">": GreaterThan + "<": LessThan + "#": Hash + ".": Dot + "*": Asterisk + "^": Caret + "%": Percent + "_": Underscore + "@": At + "!": Bang + "?": Question + "/": Slash + "\\": Backslash + ":": Colon + ";": Semicolon + "'": Apos + "\"": Quote + "`": Backtick + "(": LParen + ")": RParen + "[": LBracket + "]": RBracket + "{": LBrace + "}": RBrace + +# Name substitutions: direct overrides for specific generated names. +name-substitutions: + # Override type names during generation. + type-names: + foo: MyCustomFoo # Schema "foo" generates type "MyCustomFoo" instead of "Foo" + # Override property/field names during generation. + property-names: + bar: MyCustomBar # Property "bar" generates field "MyCustomBar" instead of "Bar" + +# Import mapping: resolve external $ref targets to Go packages. +# Required when your spec references schemas from other files. +import-mapping: + ../common/api.yaml: github.com/org/project/common + https://example.com/specs/shared.yaml: github.com/org/shared + # Use "-" to indicate types should stay in the current package + ./local-types.yaml: "-" + +# Content types: regexp patterns controlling which media types generate models. +# Only request/response bodies with matching content types will have types generated. +# Default: JSON types only. +content-types: + - "^application/json$" + - "^application/.*\\+json$" + # Add custom patterns as needed: + # - "^application/xml$" + # - "^text/plain$" + +# Content type short names: maps content type patterns to short names +# used in generated type names (e.g., "FindPetsJSONResponse"). +content-type-short-names: + - pattern: "^application/json$" + short-name: JSON + - pattern: "^application/xml$" + short-name: XML + - pattern: "^text/plain$" + short-name: Text + # ... defaults cover JSON, XML, Text, HTML, Binary, Multipart, Form + +# Struct tags: controls which struct tags are generated and their format. +# Uses Go text/template syntax. If specified, completely replaces the defaults. +# Default: json and form tags. +struct-tags: + tags: + - name: json + template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{if .OmitZero}},omitzero{{end}}{{end}}' + - name: form + template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{end}}' + # Add additional tags: + - name: yaml + template: '{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}' + - name: db + template: '{{ .FieldName }}' +``` + +## Struct tag template variables + +The struct tag templates have access to the following fields: + +| Variable | Type | Description | +|----------|------|-------------| +| `.FieldName` | `string` | The original field name from the OpenAPI spec | +| `.GoFieldName` | `string` | The Go identifier name after name mangling | +| `.IsOptional` | `bool` | Whether the field is optional in the schema | +| `.IsNullable` | `bool` | Whether the field is nullable | +| `.IsPointer` | `bool` | Whether the field is rendered as a pointer type | +| `.OmitEmpty` | `bool` | Whether `omitempty` should be applied (from extensions or optionality) | +| `.OmitZero` | `bool` | Whether `omitzero` should be applied (from `x-oapi-codegen-omitzero` extension) | +| `.JSONIgnore` | `bool` | Whether the field should be ignored in JSON (from `x-go-json-ignore` extension) | diff --git a/experimental/Makefile b/experimental/Makefile new file mode 100644 index 0000000000..a2ddf18fb1 --- /dev/null +++ b/experimental/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + @echo "Skipping tests in experimental module" + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/README.md b/experimental/README.md new file mode 100644 index 0000000000..4ce7d6310a --- /dev/null +++ b/experimental/README.md @@ -0,0 +1,164 @@ +# `oapi-codegen` V3 + +This is an experimental prototype of a V3 version of oapi-codegen. The generated code and command line options are not yet stable. Use at your +own risk. + +## What is new in Version 3 +This directory contains an experimental version of oapi-codegen's future V3 version, which is based on [libopenapi](https://github.com/pb33f/libopenapi), +instead of the prior [kin-openapi](https://github.com/getkin/kin-openapi). This change necessitated a nearly complete rewrite, but we strive to be as +compatible as possible. + +What is working: + - All model, client and server generation as in earlier versions. + - We have added Webhook and Callback support, please see `./examples`, which contains the ubiquitous OpenAPI pet shop implemented in all supported servers + and examples of webhooks and callbacks implemented on top of the `http.ServeMux` server, with no additional imports. + - Model generation of `allOf`, `anyOf`, `oneOf` is much more robust, since these were a source of many problems in earlier versions. + - Echo V5 support has been added (Go 1.25 required) + +What is missing: + - We have not yet created any runtime code like request validation middleware. + +## Differences in V3 + +V3 is a brand new implementation, and may (will) contain new bugs, but also strives to fix many current, existing bugs. We've run quite a few +conformance tests against specifications in old Issues, and we're looking pretty good! Please try this out, and if it failes in some way, please +file Issues. + +### Aggregate Schemas + +V3 implements `oneOf`, `anyOf`, `allOf` differently. Our prior versions had pretty good handling for `allOf`, where we merge all the constituent schemas +into a schema object that contains all the fields of the originals. It makes sense, since this is composition. + +`oneOf` and `anyOf` were handled by deferred parsing, where the JSON was captured into `json.RawMessage` and helper functions were created on each +type to parse the JSON as any constituent type with the user's help. + +Given the following schemas: + +```yaml +components: + schemas: + Cat: + type: object + properties: + name: + type: string + color: + type: string + Dog: + type: object + properties: + name: + type: string + color: + type: string + Fish: + type: object + properties: + species: + type: string + isSaltwater: + type: boolean + NamedPet: + anyOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + SpecificPet: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + - $ref: '#/components/schemas/Fish' +``` + +#### V2 output + +V2 generates both `NamedPet` (anyOf) and `SpecificPet` (oneOf) identically as opaque wrappers around `json.RawMessage`: + +```go +type NamedPet struct { + union json.RawMessage +} + +type SpecificPet struct { + union json.RawMessage +} +``` + +The actual variant types are invisible at the struct level. To access the underlying data, the user must call generated helper methods: + +```go +// NamedPet (anyOf) helpers +func (t NamedPet) AsCat() (Cat, error) +func (t *NamedPet) FromCat(v Cat) error +// + +// SpecificPet (oneOf) helpers + +func (t SpecificPet) AsFish() (Fish, error) +func (t *SpecificPet) FromFish(v Fish) error +func (t *SpecificPet) MergeFish(v Fish) error +// +``` + +Note that `anyOf` and `oneOf` produce identical types and method signatures; there is no semantic difference in the generated code. + +#### V3 output + +V3 generates structs with exported pointer fields for each variant, making the union members visible at the type level. Crucially, `anyOf` and `oneOf` now have different marshal/unmarshal semantics. + +**`anyOf` (NamedPet)** — `MarshalJSON` merges all non-nil variants into a single JSON object. `UnmarshalJSON` tries every variant and keeps whichever succeed: + +```go +type NamedPet struct { + Cat *Cat + Dog *Dog +} + +``` + +**`oneOf` (SpecificPet)** — `MarshalJSON` returns an error unless exactly one field is non-nil. `UnmarshalJSON` returns an error unless the JSON matches exactly one variant: + +```go +type SpecificPet struct { + Cat *Cat + Dog *Dog + Fish *Fish +} +``` + +### OpenAPI V3.1 Feature Support + +Thanks to [libopenapi](https://github.com/pb33f/libopenapi), we are able to parse OpenAPI 3.1 and 3.2 specifications. They are functionally similar, you can +read the differences between `nullable` fields yourself, but they add some new functionality, namely `webhooks` and `callbacks`. We support all of them in +this prototype. `callbacks` and `webhooks` are basically the inverse of `paths`. Webhooks contain no URL element in their definition, so we can't register handlers +for you in your http router of choice, you have to do that yourself. Callbacks support complex request URL's which may reference the original request. This is +something you need to pull out of the request body, and doing it generically is difficult, so we punt this problem, for now, to our users. + +Please see the [webhook example](examples/webhook/). It creates a little server that pretends to be a door badge reader, and it generates an event stream +about people coming and going. Any number of clients may subscribe to this event. See the [doc.go](examples/webhook/doc.go) for usage examples. + +The [callback example](examples/callback), creates a little server that pretends to plant trees. Each tree planting request contains a callback to be notified +when tree planting is complete. We invoke those in a random order via delays, and the client prints out callbacks as they happen. Please see [doc.go](examples/callback/doc.go) for usage. + +### Flexible Configuration + +oapi-codegen V3 tries to make no assumptions about which initialisms, struct tags, or name mangling that is correct for you. A very [flexible configuration file](Configuration.md) allows you to override anything. + + +### No runtime dependency + +V2 generated code relied on `github.com/oapi-codegen/runtime` for parameter binding and styling. This was a complaint from lots of people due to various +audit requirements. V3 embeds all necessary helper functions and helper types into the spec. There are no longer generic, parameterized functions that +handle arbitrary parameters, but rather very specific functions for each kind of parameter, and we call the correct little helper versus a generic +runtime helper. + + +## Installation + +Go 1.24 is required, install like so: + + go get -tool github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen@latest + +You can then run the code generator + + //go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen + diff --git a/experimental/cmd/oapi-codegen/main.go b/experimental/cmd/oapi-codegen/main.go new file mode 100644 index 0000000000..24c5320c90 --- /dev/null +++ b/experimental/cmd/oapi-codegen/main.go @@ -0,0 +1,105 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel" + + "gopkg.in/yaml.v3" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen" +) + +func main() { + configPath := flag.String("config", "", "path to configuration file") + flagPackage := flag.String("package", "", "Go package name for generated code") + flagOutput := flag.String("output", "", "output file path (default: .gen.go)") + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "Arguments:\n") + fmt.Fprintf(os.Stderr, " spec-path path to OpenAPI spec file\n\n") + fmt.Fprintf(os.Stderr, "Options:\n") + flag.PrintDefaults() + } + flag.Parse() + + if flag.NArg() != 1 { + flag.Usage() + os.Exit(1) + } + + specPath := flag.Arg(0) + + // Parse the OpenAPI spec + specData, err := os.ReadFile(specPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading spec: %v\n", err) + os.Exit(1) + } + + // Configure libopenapi to skip resolving external references. + // We handle external $refs via import mappings — the referenced specs + // don't need to be fetched or parsed. See pb33f/libopenapi#519. + docConfig := datamodel.NewDocumentConfiguration() + docConfig.SkipExternalRefResolution = true + + doc, err := libopenapi.NewDocumentWithConfiguration(specData, docConfig) + if err != nil { + fmt.Fprintf(os.Stderr, "error parsing spec: %v\n", err) + os.Exit(1) + } + + // Parse config if provided, otherwise use empty config + var cfg codegen.Configuration + if *configPath != "" { + configData, err := os.ReadFile(*configPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading config: %v\n", err) + os.Exit(1) + } + if err := yaml.Unmarshal(configData, &cfg); err != nil { + fmt.Fprintf(os.Stderr, "error parsing config: %v\n", err) + os.Exit(1) + } + } + + // Flags override config file values + if *flagPackage != "" { + cfg.PackageName = *flagPackage + } + if *flagOutput != "" { + cfg.Output = *flagOutput + } + + // Default output to .gen.go + if cfg.Output == "" { + base := filepath.Base(specPath) + ext := filepath.Ext(base) + cfg.Output = strings.TrimSuffix(base, ext) + ".gen.go" + } + + // Default package name from output file + if cfg.PackageName == "" { + cfg.PackageName = "api" + } + + // Generate code + code, err := codegen.Generate(doc, specData, cfg) + if err != nil { + fmt.Fprintf(os.Stderr, "error generating code: %v\n", err) + os.Exit(1) + } + + // Write output + if err := os.WriteFile(cfg.Output, []byte(code), 0644); err != nil { + fmt.Fprintf(os.Stderr, "error writing output: %v\n", err) + os.Exit(1) + } + + fmt.Printf("Generated %s\n", cfg.Output) +} diff --git a/experimental/examples/callback/client/main.go b/experimental/examples/callback/client/main.go new file mode 100644 index 0000000000..9e618448a3 --- /dev/null +++ b/experimental/examples/callback/client/main.go @@ -0,0 +1,144 @@ +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "log" + "net" + "net/http" + "sync" + "sync/atomic" + + treefarm "github.com/oapi-codegen/oapi-codegen/experimental/examples/callback" +) + +// trees and cities for our planting requests +var treeKinds = []string{ + "oak", "maple", "pine", "birch", "willow", + "cedar", "elm", "ash", "cherry", "walnut", +} + +var cities = []string{ + "Providence", "Austin", "Denver", "Seattle", "Chicago", + "Boston", "Miami", "Nashville", "Savannah", "Mountain View", +} + +// CallbackReceiver implements treefarm.CallbackReceiverInterface. +type CallbackReceiver struct { + received atomic.Int32 + total int + done chan struct{} + once sync.Once + + mu sync.Mutex + ordinals map[string]int // UUID string -> 1-based planting order +} + +var _ treefarm.CallbackReceiverInterface = (*CallbackReceiver)(nil) + +func NewCallbackReceiver(total int) *CallbackReceiver { + return &CallbackReceiver{ + total: total, + done: make(chan struct{}), + ordinals: make(map[string]int), + } +} + +func (cr *CallbackReceiver) Register(id string, ordinal int) { + cr.mu.Lock() + cr.ordinals[id] = ordinal + cr.mu.Unlock() +} + +func (cr *CallbackReceiver) HandleTreePlantedCallback(w http.ResponseWriter, r *http.Request) { + var result treefarm.TreePlantingResult + if err := json.NewDecoder(r.Body).Decode(&result); err != nil { + log.Printf("Error decoding callback: %v", err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + cr.mu.Lock() + ordinal := cr.ordinals[result.ID.String()] + cr.mu.Unlock() + + n := cr.received.Add(1) + log.Printf("Callback %d/%d received: tree #%d success=%v", n, cr.total, ordinal, result.Success) + + w.WriteHeader(http.StatusOK) + + if int(n) >= cr.total { + cr.once.Do(func() { close(cr.done) }) + } +} + +func main() { + serverAddr := flag.String("server", "http://localhost:8080", "Tree farm server address") + flag.Parse() + + const numTrees = 10 + + // Start callback receiver on an ephemeral port. + receiver := NewCallbackReceiver(numTrees) + + mux := http.NewServeMux() + mux.Handle("/tree_callback", treefarm.TreePlantedCallbackHandler(receiver, nil)) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatalf("Failed to listen: %v", err) + } + callbackPort := listener.Addr().(*net.TCPAddr).Port + callbackURL := fmt.Sprintf("http://localhost:%d/tree_callback", callbackPort) + log.Printf("Callback receiver listening on port %d", callbackPort) + + go func() { + if err := http.Serve(listener, mux); err != nil { + log.Printf("Callback server stopped: %v", err) + } + }() + + // Send 10 tree planting requests. + client := &http.Client{} + for i := range numTrees { + req := treefarm.TreePlantingRequest{ + Kind: treeKinds[i], + Location: cities[i], + CallbackURL: callbackURL, + } + + body, err := json.Marshal(req) + if err != nil { + log.Fatalf("Failed to marshal request: %v", err) + } + + resp, err := client.Post( + *serverAddr+"/api/plant_tree", + "application/json", + bytes.NewReader(body), + ) + if err != nil { + log.Fatalf("Failed to plant tree %d: %v", i+1, err) + } + + var accepted treefarm.TreeWithID + if err := json.NewDecoder(resp.Body).Decode(&accepted); err != nil { + _ = resp.Body.Close() + log.Fatalf("Failed to decode response: %v", err) + } + _ = resp.Body.Close() + + receiver.Register(accepted.ID.String(), i+1) + log.Printf("Planted tree %d/%d: id=%s kind=%q location=%q", + i+1, numTrees, accepted.ID, accepted.Kind, accepted.Location) + } + + log.Printf("All %d trees planted, waiting for callbacks...", numTrees) + + // Wait for all callbacks. + <-receiver.done + + log.Printf("All %d callbacks received, done!", numTrees) +} diff --git a/experimental/examples/callback/config.yaml b/experimental/examples/callback/config.yaml new file mode 100644 index 0000000000..29392d1127 --- /dev/null +++ b/experimental/examples/callback/config.yaml @@ -0,0 +1,6 @@ +package: treefarm +output: treefarm.gen.go +generation: + callback-initiator: true + callback-receiver: true + server: std-http diff --git a/experimental/examples/callback/doc.go b/experimental/examples/callback/doc.go new file mode 100644 index 0000000000..c441b88a3a --- /dev/null +++ b/experimental/examples/callback/doc.go @@ -0,0 +1,13 @@ +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config config.yaml tree-farm.yaml + +// Package treefarm provides an example of how to handle OpenAPI callbacks. +// We create a server which plants trees. The client asks the server to plant +// a tree and requests a callback when the planting is done. +// +// The server program will wait 1-5 seconds before notifying the client that a +// tree has been planted. +// +// You can run the example by running these two commands in parallel +// go run ./server --port 8080 +// go run ./client --server http://localhost:8080 +package treefarm diff --git a/experimental/examples/callback/server/main.go b/experimental/examples/callback/server/main.go new file mode 100644 index 0000000000..4b255de3b6 --- /dev/null +++ b/experimental/examples/callback/server/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "log" + "math/rand/v2" + "net" + "net/http" + "time" + + "github.com/google/uuid" + + treefarm "github.com/oapi-codegen/oapi-codegen/experimental/examples/callback" +) + +// TreeFarm implements treefarm.ServerInterface. +type TreeFarm struct { + initiator *treefarm.CallbackInitiator +} + +var _ treefarm.ServerInterface = (*TreeFarm)(nil) + +func NewTreeFarm() *TreeFarm { + initiator, err := treefarm.NewCallbackInitiator() + if err != nil { + log.Fatalf("Failed to create callback initiator: %v", err) + } + return &TreeFarm{initiator: initiator} +} + +func sendError(w http.ResponseWriter, code int, message string) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(treefarm.Error{ + Code: int32(code), + Message: message, + }) +} + +func (tf *TreeFarm) PlantTree(w http.ResponseWriter, r *http.Request) { + log.Printf("Received PlantTree request from %s", r.RemoteAddr) + + var req treefarm.TreePlantingRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + sendError(w, http.StatusBadRequest, "Invalid request body: "+err.Error()) + return + } + + if req.CallbackURL == "" { + sendError(w, http.StatusBadRequest, "callbackUrl is required") + return + } + + id := uuid.New() + + log.Printf("Accepted tree planting: id=%s kind=%q location=%q callbackUrl=%q", + id, req.Kind, req.Location, req.CallbackURL) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _ = json.NewEncoder(w).Encode(treefarm.TreeWithID{ + Location: req.Location, + Kind: req.Kind, + ID: id, + }) + + go tf.plantAndNotify(id, req) +} + +func (tf *TreeFarm) plantAndNotify(id uuid.UUID, req treefarm.TreePlantingRequest) { + delay := time.Duration(1+rand.IntN(5)) * time.Second + log.Printf("Planting tree %s (kind=%q, location=%q) — will complete in %s", + id, req.Kind, req.Location, delay) + + time.Sleep(delay) + + result := treefarm.TreePlantedJSONRequestBody{ + ID: id, + Kind: req.Kind, + Location: req.Location, + Success: true, + } + + log.Printf("Tree %s planted, invoking callback at %s", id, req.CallbackURL) + + resp, err := tf.initiator.TreePlanted(context.Background(), req.CallbackURL, result) + if err != nil { + log.Printf("Callback to %s failed: %v", req.CallbackURL, err) + return + } + defer func() { _ = resp.Body.Close() }() + + log.Printf("Callback to %s returned status %d", req.CallbackURL, resp.StatusCode) +} + +func main() { + port := flag.String("port", "8080", "Port for HTTP server") + flag.Parse() + + farm := NewTreeFarm() + + mux := http.NewServeMux() + treefarm.HandlerFromMux(farm, mux) + + // Wrap with request logging. + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Printf("%s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) + mux.ServeHTTP(w, r) + }) + + addr := net.JoinHostPort("0.0.0.0", *port) + log.Printf("Tree Farm server listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, handler)) +} diff --git a/experimental/examples/callback/tree-farm.yaml b/experimental/examples/callback/tree-farm.yaml new file mode 100644 index 0000000000..4cad525c08 --- /dev/null +++ b/experimental/examples/callback/tree-farm.yaml @@ -0,0 +1,138 @@ +openapi: "3.1.0" +info: + version: 1.0.0 + title: Tree Farm + description: | + A tree planting service that demonstrates OpenAPI callbacks. + The client submits a tree planting request along with a callback URL. + When the tree has been planted, the server sends a POST to the callback URL + to notify the client of the result. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +paths: + /api/plant_tree: + post: + summary: Request a tree planting + description: | + Submits a request to plant a tree at the specified location. + This is a long-running operation — the server accepts the request + and later notifies the caller via the provided callback URL. + operationId: PlantTree + requestBody: + $ref: '#/components/requestBodies/TreePlanting' + responses: + '202': + description: Tree planting request accepted + content: + application/json: + schema: + $ref: '#/components/schemas/TreeWithId' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + callbacks: + treePlanted: + '{$request.body#/callbackUrl}': + post: + summary: Tree planting result notification + description: | + Sent by the server to the callback URL when the tree planting + operation completes (successfully or not). + operationId: TreePlanted + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TreePlantingResult' + responses: + '200': + description: Callback received successfully + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +components: + schemas: + Tree: + type: object + description: A tree to be planted + required: + - location + - kind + properties: + location: + type: string + description: Where to plant the tree (e.g. "north meadow") + kind: + type: string + description: What kind of tree to plant (e.g. "oak") + + TreePlantingRequest: + description: | + A tree planting request, combining the tree details with a callback URL + for completion notification. + allOf: + - $ref: '#/components/schemas/Tree' + - type: object + required: + - callbackUrl + properties: + callbackUrl: + type: string + format: uri + description: URL to receive the planting result callback + + TreeWithId: + description: A tree with a server-assigned identifier + allOf: + - $ref: '#/components/schemas/Tree' + - type: object + required: + - id + properties: + id: + type: string + format: uuid + description: Unique identifier for this planting request + + TreePlantingResult: + description: The result of a tree planting operation, sent via callback + allOf: + - $ref: '#/components/schemas/TreeWithId' + - type: object + required: + - success + properties: + success: + type: boolean + description: Whether the tree was successfully planted + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message + + requestBodies: + TreePlanting: + description: Tree planting request + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TreePlantingRequest' diff --git a/experimental/examples/callback/treefarm.gen.go b/experimental/examples/callback/treefarm.gen.go new file mode 100644 index 0000000000..a1018c08e9 --- /dev/null +++ b/experimental/examples/callback/treefarm.gen.go @@ -0,0 +1,503 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package treefarm + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "sync" + + "github.com/google/uuid" +) + +// #/components/schemas/Tree +// A tree to be planted +type Tree struct { + Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") + Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Tree) ApplyDefaults() { +} + +// #/components/schemas/TreePlantingRequest +// A tree planting request, combining the tree details with a callback URL +// for completion notification. +type TreePlantingRequest struct { + Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") + Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") + CallbackURL string `json:"callbackUrl" form:"callbackUrl"` // URL to receive the planting result callback +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TreePlantingRequest) ApplyDefaults() { +} + +// #/components/schemas/TreeWithId +// A tree with a server-assigned identifier +type TreeWithID struct { + Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") + Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") + ID UUID `json:"id" form:"id"` // Unique identifier for this planting request +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TreeWithID) ApplyDefaults() { +} + +// #/components/schemas/TreePlantingResult +// The result of a tree planting operation, sent via callback +type TreePlantingResult struct { + Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") + Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") + ID UUID `json:"id" form:"id"` // Unique identifier for this planting request + Success bool `json:"success" form:"success"` // Whether the tree was successfully planted +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TreePlantingResult) ApplyDefaults() { +} + +// #/components/schemas/Error +type Error struct { + Code int32 `json:"code" form:"code"` // Error code + Message string `json:"message" form:"message"` // Error message +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Error) ApplyDefaults() { +} + +type UUID = uuid.UUID + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/8RXwW7bOBC96ysGaQG3QCO76U23bJEFAhSbIHGQ44IWxxYbilTJUbzG7gL7EfuF+yUL", + "khJFy4rr9NKcopDzZvhm5s1EN6hYIwo4+5R/zBdnmVBrXWQAz2is0KqAj/kiX2QAJEhiAUuDCL8yU2cA", + "HG1pREP+3l8ZAMAlkLvQSKZIqA1YNM+iRKCKEXCstbJkGKGFmwbV5e01lEzKFSufbO4BlhVCKQUqAtuu", + "akEW2AjT4LcWLQGTWm1gK6gCFmHg4e5LQHqsUAFVGKwrZmGFqAIM8g/+yIWHBiwq7vzc3twvgbQ/SgE9", + "HmlQmsR6F45DjHrtvwzaVpLzK0WJymLhTRSrsYDLhpUVwoWnEaA1soCKqLHFfL7dbnPmz3NtNvPO2s6/", + "XH+++u3+6vwiX+QV1TJrGFXWoc5ZI+b+Eb+7hwVHjbYUfgOwbV0zsyvgrudpn7/u2kTy3M99JL2nmXQw", + "7XEYBeoaLMVaIAepS+Zg8giyrIQF4UBcis5Nq5RLnG7Q+Jvw3z//pvyzssSGbEeldxuxmOIgGaEJ7Au0", + "MT1o4Fkw/9kY/Sw48ok6gMHvNS/g1r3FVXF32Pn7RfNdEZ2+NbguYPZmXuq60QoV2flwUaCdO4TbjtFZ", + "hLKNdukbgGYXi4vZ8DmifTld154N5IlVqRWhohQIgDWNFIH6+Ver1f4pgC0rrNn4r9OPC3fDsx4FVdd8", + "lg0hr1kr6cVXtAr/aLAk5IDGaPMz4r5yjvuQo6QMGNSnC3kKPPvzbcd6vtJ892bemz4Y+fdsP4S0x2Ko", + "fa+NM+nkoCvY8NKR4QvdF7vQactql/bIhCzBdk/iRg0+/Ax955iT6OT3nW3LEq1dt1LuQPvuep9nLxi6", + "xlkOFI6uTbZQeigM8gLItHhwPFkhp9XJ8Wo5rdb7Fr7zGZsdPOygoZPGXsymvO5l9nOfLYMlimfkkNKe", + "HdoedNprO+4EXk9l9nvcntSRw4mD6Q4D4jKOLwDaNViAXn3FkqYGVLdXkIYV9iM8GxVYDPM8jqTkT09C", + "9RaNcYVNIs1rb5E+NgRlyew31V5gjxUaHGZkbMZ3mG9yOFPaUAU1Mq63Z+8jiAvm9Z4YeUO/dHRsBK+d", + "M82ezt5nkduhtn17FscH/+X0lvXBacZK+PkdH8eRmJB2aveKeGtterlxypNqYS8zTMqbdZq273XrLLk7", + "UTHT1RCuJ8KenExVQjpBHowcV/8LqeqeXDMqoDXimNw75SbdS0JYX0aTo/c/JDMM5eJIb3TJCOPinFkr", + "Ngo5CI7K703mJ7Au+AlkC/4jHLeCHyVZiW8tJq/3BUluMR2X+FTH2ESG91e2uO27Nhz/axIH5gf3PwX5", + "9TTm8gfpH69jr05CN3JOyER3czodK60lsqOLzGOFVLldpReKLbN7Ey9Kt0fxI+LIBJhS9lJzTD5rtJZt", + "8IiwO4NDqRWKcIPp4OwLSyj6dPGSBvuI92PoInitmgekPvwsXaJi+GlJThfjlGJnR/aug63g2CYwNf1P", + "36d8LLPs/wAAAP//y9dX5mEQAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Request a tree planting + // (POST /api/plant_tree) + PlantTree(w http.ResponseWriter, r *http.Request) +} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +// PlantTree operation middleware +func (siw *ServerInterfaceWrapper) PlantTree(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.PlantTree(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +// StdHTTPServerOptions configures the StdHTTP server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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("POST "+options.BaseURL+"/api/plant_tree", wrapper.PlantTree) + return m +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +type TreePlantedJSONRequestBody = TreePlantingResult + +// RequestEditorFn is the function signature for the RequestEditor callback function. +// It may already be defined if client code is also generated; this is a compatible redeclaration. +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// HttpRequestDoer performs HTTP requests. +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// CallbackInitiator sends callback requests to target URLs. +// Unlike Client, it has no stored base URL — the full target URL is provided per-call. +type CallbackInitiator struct { + // 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 +} + +// CallbackInitiatorOption allows setting custom parameters during construction. +type CallbackInitiatorOption func(*CallbackInitiator) error + +// NewCallbackInitiator creates a new CallbackInitiator with reasonable defaults. +func NewCallbackInitiator(opts ...CallbackInitiatorOption) (*CallbackInitiator, error) { + initiator := CallbackInitiator{} + for _, o := range opts { + if err := o(&initiator); err != nil { + return nil, err + } + } + if initiator.Client == nil { + initiator.Client = &http.Client{} + } + return &initiator, nil +} + +// WithCallbackHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithCallbackHTTPClient(doer HttpRequestDoer) CallbackInitiatorOption { + return func(p *CallbackInitiator) error { + p.Client = doer + return nil + } +} + +// WithCallbackRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithCallbackRequestEditorFn(fn RequestEditorFn) CallbackInitiatorOption { + return func(p *CallbackInitiator) error { + p.RequestEditors = append(p.RequestEditors, fn) + return nil + } +} + +func (p *CallbackInitiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range p.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 +} + +// CallbackInitiatorInterface is the interface specification for the callback initiator. +type CallbackInitiatorInterface interface { + // TreePlantedWithBody sends a POST callback request + TreePlantedWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + TreePlanted(ctx context.Context, targetURL string, body TreePlantedJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +// TreePlantedWithBody sends a POST callback request +// Tree planting result notification +func (p *CallbackInitiator) TreePlantedWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewTreePlantedCallbackRequestWithBody(targetURL, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// TreePlanted sends a POST callback request with JSON body +func (p *CallbackInitiator) TreePlanted(ctx context.Context, targetURL string, body TreePlantedJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewTreePlantedCallbackRequest(targetURL, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// NewTreePlantedCallbackRequest creates a POST request for the callback with application/json body +func NewTreePlantedCallbackRequest(targetURL string, body TreePlantedJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewTreePlantedCallbackRequestWithBody(targetURL, "application/json", bodyReader) +} + +// NewTreePlantedCallbackRequestWithBody creates a POST request for the callback with any body +func NewTreePlantedCallbackRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + parsedURL, err := url.Parse(targetURL) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", parsedURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// CallbackHttpError represents an HTTP error response. +// The type parameter E is the type of the parsed error body. +type CallbackHttpError[E any] struct { + StatusCode int + Body E + RawBody []byte +} + +func (e *CallbackHttpError[E]) Error() string { + return fmt.Sprintf("HTTP %d", e.StatusCode) +} + +// SimpleCallbackInitiator wraps CallbackInitiator with typed responses for operations that have +// unambiguous response types. Methods return the success type directly, +// and HTTP errors are returned as *CallbackHttpError[E] where E is the error type. +type SimpleCallbackInitiator struct { + *CallbackInitiator +} + +// NewSimpleCallbackInitiator creates a new SimpleCallbackInitiator which wraps a CallbackInitiator. +func NewSimpleCallbackInitiator(opts ...CallbackInitiatorOption) (*SimpleCallbackInitiator, error) { + initiator, err := NewCallbackInitiator(opts...) + if err != nil { + return nil, err + } + return &SimpleCallbackInitiator{CallbackInitiator: initiator}, nil +} + +// CallbackReceiverInterface represents handlers for receiving callback requests. +type CallbackReceiverInterface interface { + // Tree planting result notification + // HandleTreePlantedCallback handles the POST callback request. + HandleTreePlantedCallback(w http.ResponseWriter, r *http.Request) +} + +// CallbackReceiverMiddlewareFunc is a middleware function for callback receiver handlers. +type CallbackReceiverMiddlewareFunc func(http.Handler) http.Handler + +// TreePlantedCallbackHandler returns an http.Handler for the TreePlanted callback. +// The caller is responsible for registering this handler at the appropriate path. +func TreePlantedCallbackHandler(si CallbackReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...CallbackReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.HandleTreePlantedCallback(w, r) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} diff --git a/experimental/examples/petstore-expanded/chi/Makefile b/experimental/examples/petstore-expanded/chi/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/chi/go.mod b/experimental/examples/petstore-expanded/chi/go.mod new file mode 100644 index 0000000000..3c9d10741e --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/go.mod @@ -0,0 +1,11 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/chi + +go 1.24.0 + +require ( + github.com/go-chi/chi/v5 v5.2.0 + github.com/google/uuid v1.6.0 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/chi/go.sum b/experimental/examples/petstore-expanded/chi/go.sum new file mode 100644 index 0000000000..ad495c8907 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/go.sum @@ -0,0 +1,4 @@ +github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= +github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +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= diff --git a/experimental/examples/petstore-expanded/chi/main.go b/experimental/examples/petstore-expanded/chi/main.go new file mode 100644 index 0000000000..8a4e0e3790 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/main.go @@ -0,0 +1,40 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/chi/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + r := chi.NewRouter() + + // We now register our petStore above as the handler for the interface + server.HandlerFromMux(petStore, r) + + s := &http.Server{ + Handler: r, + Addr: net.JoinHostPort("0.0.0.0", *port), + } + + log.Printf("Server listening on %s", s.Addr) + + // And we serve HTTP until the world ends. + log.Fatal(s.ListenAndServe()) +} diff --git a/experimental/examples/petstore-expanded/chi/server/petstore.go b/experimental/examples/petstore-expanded/chi/server/petstore.go new file mode 100644 index 0000000000..2f52c8e271 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/server/petstore.go @@ -0,0 +1,135 @@ +//go:build go1.22 + +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" + + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(w http.ResponseWriter, code int, message string) { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.Pet + + for _, pet := range p.Pets { + if params.Tags != nil { + // If we have tags, filter pets by tag + for _, t := range *params.Tags { + if pet.Tag != nil && (*pet.Tag == t) { + result = append(result, pet) + } + } + } else { + // Add all pets if we're not filtering + result = append(result, pet) + } + + if params.Limit != nil { + l := int(*params.Limit) + if len(result) >= l { + // We're at the limit + break + } + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { + sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") + return + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + delete(p.Pets, id) + + w.WriteHeader(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/chi/server/server.config.yaml b/experimental/examples/petstore-expanded/chi/server/server.config.yaml new file mode 100644 index 0000000000..b3b3509411 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: chi + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/chi/server/server.gen.go b/experimental/examples/petstore-expanded/chi/server/server.gen.go new file mode 100644 index 0000000000..167ae93385 --- /dev/null +++ b/experimental/examples/petstore-expanded/chi/server/server.gen.go @@ -0,0 +1,1039 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/go-chi/chi/v5" + "github.com/google/uuid" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) + // Creates a new pet + // (POST /pets) + AddPet(w http.ResponseWriter, r *http.Request) + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(w http.ResponseWriter, r *http.Request, id int64) + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(w http.ResponseWriter, r *http.Request, id int64) +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { + w.WriteHeader(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) + return + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPets(w, r, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.AddPet(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, chi.URLParam(r, "id"), &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeletePet(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, chi.URLParam(r, "id"), &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPetByID(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, ChiServerOptions{}) +} + +// ChiServerOptions configures the Chi server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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+"/pets", wrapper.FindPets) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/pets", wrapper.AddPet) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/pets/{id}", wrapper.DeletePet) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/pets/{id}", wrapper.FindPetByID) + }) + return r +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/client/client.config.yaml b/experimental/examples/petstore-expanded/client/client.config.yaml new file mode 100644 index 0000000000..eee5ae5073 --- /dev/null +++ b/experimental/examples/petstore-expanded/client/client.config.yaml @@ -0,0 +1,8 @@ +package: client +output: client.gen.go +generation: + client: true + simple-client: true + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/client/client.gen.go b/experimental/examples/petstore-expanded/client/client.gen.go new file mode 100644 index 0000000000..d095e9cfda --- /dev/null +++ b/experimental/examples/petstore-expanded/client/client.gen.go @@ -0,0 +1,1225 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package client + +import ( + "bytes" + "context" + "encoding" + "encoding/json" + "errors" + "fmt" + "github.com/google/uuid" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" + "io" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" +) + +type addPetJSONRequestBody = petstore.NewPet + +// RequestEditorFn is the function signature for the RequestEditor callback function. +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// HttpRequestDoer 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 + +// NewClient creates a new Client with reasonable defaults. +func NewClient(server string, opts ...ClientOption) (*Client, error) { + client := Client{ + Server: server, + } + 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 + } +} + +// 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 + } +} + +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 +} + +// ClientInterface is the interface specification for the client. +type ClientInterface interface { + // FindPets makes a GET request to /pets + FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + // AddPetWithBody makes a POST request to /pets + AddPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // DeletePet makes a DELETE request to /pets/{id} + DeletePet(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) + // FindPetByID makes a GET request to /pets/{id} + FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// FindPets makes a GET request to /pets +// Returns all pets +func (c *Client) FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewFindPetsRequest(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) +} + +// AddPetWithBody makes a POST request to /pets +// Creates a new pet +func (c *Client) AddPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewAddPetRequestWithBody(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) +} + +// AddPet makes a POST request to /pets with JSON body +func (c *Client) AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewAddPetRequest(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) +} + +// DeletePet makes a DELETE request to /pets/{id} +// Deletes a pet by ID +func (c *Client) DeletePet(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeletePetRequest(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) +} + +// FindPetByID makes a GET request to /pets/{id} +// Returns a pet by ID +func (c *Client) FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewFindPetByIDRequest(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) +} + +// NewFindPetsRequest creates a GET request for /pets +func NewFindPetsRequest(server string, params *FindPetsParams) (*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 + } + + if params != nil { + queryValues := queryURL.Query() + if params.Tags != nil { + if queryFrag, err := StyleFormExplodeParam("tags", ParamLocationQuery, *params.Tags); 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) + } + } + } + } + if params.Limit != nil { + if queryFrag, err := StyleFormExplodeParam("limit", ParamLocationQuery, *params.Limit); 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) + } + } + } + } + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewAddPetRequest creates a POST request for /pets with application/json body +func NewAddPetRequest(server string, body addPetJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewAddPetRequestWithBody(server, "application/json", bodyReader) +} + +// NewAddPetRequestWithBody creates a POST request for /pets with any body +func NewAddPetRequestWithBody(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("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewDeletePetRequest creates a DELETE request for /pets/{id} +func NewDeletePetRequest(server string, id int64) (*http.Request, error) { + var err error + + var pathParam0 string + pathParam0, err = StyleSimpleParam("id", ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/pets/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewFindPetByIDRequest creates a GET request for /pets/{id} +func NewFindPetByIDRequest(server string, id int64) (*http.Request, error) { + var err error + + var pathParam0 string + pathParam0, err = StyleSimpleParam("id", ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/pets/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// ClientHttpError represents an HTTP error response from the server. +// The type parameter E is the type of the parsed error body. +type ClientHttpError[E any] struct { + StatusCode int + Body E + RawBody []byte +} + +func (e *ClientHttpError[E]) Error() string { + return fmt.Sprintf("HTTP %d", e.StatusCode) +} + +// SimpleClient wraps Client with typed responses for operations that have +// unambiguous response types. Methods return the success type directly, +// and HTTP errors are returned as *ClientHttpError[E] where E is the error type. +type SimpleClient struct { + *Client +} + +// NewSimpleClient creates a new SimpleClient which wraps a Client. +func NewSimpleClient(server string, opts ...ClientOption) (*SimpleClient, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &SimpleClient{Client: client}, nil +} + +// FindPets makes a GET request to /pets and returns the parsed response. +// Returns all pets +// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. +func (c *SimpleClient) FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) ([]petstore.Pet, error) { + var result []petstore.Pet + resp, err := c.Client.FindPets(ctx, params, reqEditors...) + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // Parse error response + var errBody petstore.Error + _ = json.Unmarshal(rawBody, &errBody) // Best effort parse + return result, &ClientHttpError[petstore.Error]{ + StatusCode: resp.StatusCode, + Body: errBody, + RawBody: rawBody, + } +} + +// AddPet makes a POST request to /pets and returns the parsed response. +// Creates a new pet +// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. +func (c *SimpleClient) AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (petstore.Pet, error) { + var result petstore.Pet + resp, err := c.Client.AddPet(ctx, body, reqEditors...) + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // Parse error response + var errBody petstore.Error + _ = json.Unmarshal(rawBody, &errBody) // Best effort parse + return result, &ClientHttpError[petstore.Error]{ + StatusCode: resp.StatusCode, + Body: errBody, + RawBody: rawBody, + } +} + +// FindPetByID makes a GET request to /pets/{id} and returns the parsed response. +// Returns a pet by ID +// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. +func (c *SimpleClient) FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (petstore.Pet, error) { + var result petstore.Pet + resp, err := c.Client.FindPetByID(ctx, id, reqEditors...) + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // Parse error response + var errBody petstore.Error + _ = json.Unmarshal(rawBody, &errBody) // Best effort parse + return result, &ClientHttpError[petstore.Error]{ + StatusCode: resp.StatusCode, + Body: errBody, + RawBody: rawBody, + } +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/client/client_test.go b/experimental/examples/petstore-expanded/client/client_test.go new file mode 100644 index 0000000000..76ad5ef8e4 --- /dev/null +++ b/experimental/examples/petstore-expanded/client/client_test.go @@ -0,0 +1,161 @@ +package client + +import ( + "context" + "net/http" + "testing" + + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestClientTypes verifies all generated types exist and have correct structure. +// If this test compiles, the type generation is correct. +func TestClientTypes(t *testing.T) { + // Core client types + var _ *Client + var _ *SimpleClient + var _ ClientInterface + var _ ClientOption + var _ RequestEditorFn + var _ HttpRequestDoer + + // Param types + var _ *FindPetsParams + + // Request body type alias + var _ addPetJSONRequestBody + + // Error type with generic parameter + var _ *ClientHttpError[petstore.Error] +} + +// TestClientStructure verifies Client struct has expected fields by accessing them. +func TestClientStructure(t *testing.T) { + c := &Client{} + + // Access fields - compiler validates they exist with correct types + var _ = c.Server + var _ = c.Client + var _ = c.RequestEditors +} + +// TestClientImplementsInterface verifies Client implements ClientInterface. +func TestClientImplementsInterface(t *testing.T) { + var _ ClientInterface = (*Client)(nil) +} + +// TestClientInterfaceMethods verifies ClientInterface methods exist with correct signatures. +// The fact that Client implements ClientInterface (tested above) validates all method signatures. +// Here we use method expressions to verify exact signatures without needing an instance. +func TestClientInterfaceMethods(t *testing.T) { + // Method expressions verify signatures at compile time + var _ = (*Client).FindPets + var _ = (*Client).AddPetWithBody + var _ = (*Client).AddPet + var _ = (*Client).DeletePet + var _ = (*Client).FindPetByID +} + +// TestSimpleClientMethods verifies SimpleClient methods return typed responses. +func TestSimpleClientMethods(t *testing.T) { + // Use method expressions to verify signatures without needing an instance + // Compiler validates return types - these use the petstore package types + var _ = (*SimpleClient).FindPets + var _ = (*SimpleClient).AddPet + var _ = (*SimpleClient).FindPetByID +} + +// TestFindPetsParamsStructure verifies param struct fields. +func TestFindPetsParamsStructure(t *testing.T) { + p := &FindPetsParams{} + + // Access fields - compiler validates they exist with correct types + var _ = p.Tags + var _ = p.Limit +} + +// TestRequestBodyTypeAlias verifies the type alias points to correct type. +func TestRequestBodyTypeAlias(t *testing.T) { + // Compiler validates the alias is compatible with petstore.NewPet + var body addPetJSONRequestBody + var newPet petstore.NewPet + + // Bidirectional assignment proves they're the same type + body = newPet + newPet = body + _ = body + _ = newPet +} + +// TestPetstoreTypes verifies that generated types use short names directly. +func TestPetstoreTypes(t *testing.T) { + // Types should be defined directly with short names (no SchemaComponent suffix) + var _ petstore.Pet + var _ petstore.NewPet + var _ petstore.Error +} + +// TestClientHttpErrorImplementsError verifies ClientHttpError implements error interface. +func TestClientHttpErrorImplementsError(t *testing.T) { + var _ error = (*ClientHttpError[petstore.Error])(nil) +} + +// TestClientHttpErrorStructure verifies error type fields. +func TestClientHttpErrorStructure(t *testing.T) { + e := &ClientHttpError[petstore.Error]{} + + // Access fields - compiler validates they exist with correct types + var _ = e.StatusCode + var _ = e.Body + var _ = e.RawBody +} + +// TestRequestBuilders verifies request builder functions exist with correct signatures. +func TestRequestBuilders(t *testing.T) { + var _ = NewFindPetsRequest + var _ = NewAddPetRequestWithBody + var _ = NewAddPetRequest + var _ = NewDeletePetRequest + var _ = NewFindPetByIDRequest +} + +// TestNewClientConstructor verifies the constructor works correctly. +func TestNewClientConstructor(t *testing.T) { + client, err := NewClient("https://api.example.com") + require.NoError(t, err) + require.NotNil(t, client) + + // Verify trailing slash is added + assert.Equal(t, "https://api.example.com/", client.Server) + // Verify default http.Client is created + assert.NotNil(t, client.Client) +} + +// TestClientOptions verifies client options work correctly. +func TestClientOptions(t *testing.T) { + customClient := &http.Client{} + + client, err := NewClient("https://api.example.com", + WithHTTPClient(customClient), + WithRequestEditorFn(func(ctx context.Context, req *http.Request) error { + req.Header.Set("X-Custom", "value") + return nil + }), + ) + require.NoError(t, err) + + assert.Equal(t, customClient, client.Client) + assert.Len(t, client.RequestEditors, 1) +} + +// TestClientHttpErrorMessage verifies the error message format. +func TestClientHttpErrorMessage(t *testing.T) { + err := &ClientHttpError[petstore.Error]{ + StatusCode: 404, + Body: petstore.Error{Code: 404, Message: "Not Found"}, + } + + assert.Contains(t, err.Error(), "404") +} diff --git a/experimental/examples/petstore-expanded/client/validator/main.go b/experimental/examples/petstore-expanded/client/validator/main.go new file mode 100644 index 0000000000..d84632f301 --- /dev/null +++ b/experimental/examples/petstore-expanded/client/validator/main.go @@ -0,0 +1,143 @@ +package main + +import ( + "context" + "flag" + "log" + "os" + "strings" + + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/client" +) + +func ptr[T any](v T) *T { return &v } + +func main() { + serverURL := flag.String("server", "http://localhost:8080", "Petstore server URL") + flag.Parse() + + log.SetFlags(0) + log.Printf("Petstore Validator") + log.Printf("==================") + log.Printf("Server: %s", *serverURL) + log.Println() + + c, err := client.NewSimpleClient(*serverURL) + if err != nil { + log.Fatalf("Failed to create client: %v", err) + } + ctx := context.Background() + + // Step 1: Add Fido the Dog and Sushi the Cat + log.Println("--- Step 1: Creating pets ---") + + fido, err := c.AddPet(ctx, petstore.NewPet{Name: "Fido", Tag: ptr("Dog")}) + if err != nil { + log.Fatalf("Failed to create Fido: %v", err) + } + log.Printf("Created pet: %s (tag=%s, id=%d)", fido.Name, derefTag(fido.Tag), fido.ID) + + sushi, err := c.AddPet(ctx, petstore.NewPet{Name: "Sushi", Tag: ptr("Cat")}) + if err != nil { + log.Fatalf("Failed to create Sushi: %v", err) + } + log.Printf("Created pet: %s (tag=%s, id=%d)", sushi.Name, derefTag(sushi.Tag), sushi.ID) + log.Println() + + // Step 2: List all pets + log.Println("--- Step 2: Listing all pets ---") + pets, err := c.FindPets(ctx, nil) + if err != nil { + log.Fatalf("Failed to list pets: %v", err) + } + printPets(pets) + log.Println() + + // Step 3: Delete Fido + log.Printf("--- Step 3: Deleting Fido (id=%d) ---", fido.ID) + resp, err := c.DeletePet(ctx, fido.ID) + if err != nil { + log.Fatalf("Failed to delete Fido: %v", err) + } + _ = resp.Body.Close() + if resp.StatusCode == 204 { + log.Printf("Deleted Fido successfully (HTTP %d)", resp.StatusCode) + } else { + log.Fatalf("Unexpected status deleting Fido: HTTP %d", resp.StatusCode) + } + log.Println() + + // Step 4: Add Slimy the Lizard + log.Println("--- Step 4: Creating Slimy the Lizard ---") + slimy, err := c.AddPet(ctx, petstore.NewPet{Name: "Slimy", Tag: ptr("Lizard")}) + if err != nil { + log.Fatalf("Failed to create Slimy: %v", err) + } + log.Printf("Created pet: %s (tag=%s, id=%d)", slimy.Name, derefTag(slimy.Tag), slimy.ID) + log.Println() + + // Step 5: List all pets again + log.Println("--- Step 5: Listing all pets (after changes) ---") + pets, err = c.FindPets(ctx, nil) + if err != nil { + log.Fatalf("Failed to list pets: %v", err) + } + printPets(pets) + log.Println() + + // Validate final state + log.Println("--- Validation ---") + ok := true + if len(pets) != 2 { + log.Printf("FAIL: expected 2 pets, got %d", len(pets)) + ok = false + } + names := map[string]bool{} + for _, p := range pets { + names[p.Name] = true + } + if !names["Sushi"] { + log.Printf("FAIL: Sushi not found in pet list") + ok = false + } + if !names["Slimy"] { + log.Printf("FAIL: Slimy not found in pet list") + ok = false + } + if names["Fido"] { + log.Printf("FAIL: Fido should have been deleted but is still present") + ok = false + } + + if ok { + log.Println("PASS: All validations passed!") + } else { + log.Println("FAIL: Some validations failed") + os.Exit(1) + } +} + +func derefTag(tag *string) string { + if tag == nil { + return "" + } + return *tag +} + +func printPets(pets []petstore.Pet) { + if len(pets) == 0 { + log.Println(" (no pets)") + return + } + maxName := 0 + for _, p := range pets { + if len(p.Name) > maxName { + maxName = len(p.Name) + } + } + for _, p := range pets { + padding := strings.Repeat(" ", maxName-len(p.Name)) + log.Printf(" - %s%s tag=%-8s id=%d", p.Name, padding, derefTag(p.Tag), p.ID) + } +} diff --git a/experimental/examples/petstore-expanded/doc.go b/experimental/examples/petstore-expanded/doc.go new file mode 100644 index 0000000000..d3e6eede3d --- /dev/null +++ b/experimental/examples/petstore-expanded/doc.go @@ -0,0 +1,2 @@ +// Package petstore provides generated types for the Petstore API. +package petstore diff --git a/experimental/examples/petstore-expanded/echo-v4/Makefile b/experimental/examples/petstore-expanded/echo-v4/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/echo-v4/go.mod b/experimental/examples/petstore-expanded/echo-v4/go.mod new file mode 100644 index 0000000000..241f767a53 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/go.mod @@ -0,0 +1,23 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo-v4 + +go 1.24.0 + +require ( + github.com/google/uuid v1.6.0 + github.com/labstack/echo/v4 v4.13.3 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +require ( + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.33.0 // indirect +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/echo-v4/go.sum b/experimental/examples/petstore-expanded/echo-v4/go.sum new file mode 100644 index 0000000000..d6b2e1f6c1 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/go.sum @@ -0,0 +1,33 @@ +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/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/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= +github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= +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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +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/experimental/examples/petstore-expanded/echo-v4/main.go b/experimental/examples/petstore-expanded/echo-v4/main.go new file mode 100644 index 0000000000..5f89fc8cd3 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/main.go @@ -0,0 +1,34 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + + "github.com/labstack/echo/v4" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo-v4/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + e := echo.New() + + // We now register our petStore above as the handler for the interface + server.RegisterHandlers(e, petStore) + + log.Printf("Server listening on %s", net.JoinHostPort("0.0.0.0", *port)) + + // And we serve HTTP until the world ends. + log.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port))) +} diff --git a/experimental/examples/petstore-expanded/echo-v4/server/petstore.go b/experimental/examples/petstore-expanded/echo-v4/server/petstore.go new file mode 100644 index 0000000000..9ee8d05a1b --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/server/petstore.go @@ -0,0 +1,123 @@ +//go:build go1.22 + +package server + +import ( + "net/http" + "sync" + + "github.com/labstack/echo/v4" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(ctx echo.Context, code int, message string) error { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + return ctx.JSON(code, petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(ctx echo.Context, params FindPetsParams) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.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) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(ctx echo.Context) error { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := ctx.Bind(&newPet); err != nil { + return sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + return ctx.JSON(http.StatusCreated, pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(ctx echo.Context, id int64) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + return sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") + } + + return ctx.JSON(http.StatusOK, pet) +} + +// DeletePet deletes a pet by ID. +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, "Could not find pet with ID") + } + delete(p.Pets, id) + + return ctx.NoContent(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml b/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml new file mode 100644 index 0000000000..c4f40a9a65 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: echo/v4 + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go b/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go new file mode 100644 index 0000000000..af329680a5 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go @@ -0,0 +1,976 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" + "github.com/labstack/echo/v4" +) + +// 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 +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(ctx echo.Context, params FindPetsParams) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(ctx echo.Context) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(ctx echo.Context, id int64) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(ctx echo.Context, id int64) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// 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 = BindFormExplodeParam("tags", false, ctx.QueryParams(), ¶ms.Tags) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, ctx.QueryParams(), ¶ms.Limit) + 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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.FindPetByID(ctx, id) + return err +} + +// EchoRouter is an interface for echo.Echo and echo.Group. +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, "") +} + +// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. +func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { + + 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) +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/echo/Makefile b/experimental/examples/petstore-expanded/echo/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/echo/go.mod b/experimental/examples/petstore-expanded/echo/go.mod new file mode 100644 index 0000000000..3576808d2d --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/go.mod @@ -0,0 +1,11 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo + +go 1.25.0 + +require ( + github.com/google/uuid v1.6.0 + github.com/labstack/echo/v5 v5.0.0 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/echo/go.sum b/experimental/examples/petstore-expanded/echo/go.sum new file mode 100644 index 0000000000..9dd4179c6c --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/go.sum @@ -0,0 +1,16 @@ +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/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/labstack/echo/v5 v5.0.0 h1:JHKGrI0cbNsNMyKvranuY0C94O4hSM7yc/HtwcV3Na4= +github.com/labstack/echo/v5 v5.0.0/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= +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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +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/experimental/examples/petstore-expanded/echo/main.go b/experimental/examples/petstore-expanded/echo/main.go new file mode 100644 index 0000000000..6f0483ac28 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/main.go @@ -0,0 +1,34 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + + "github.com/labstack/echo/v5" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + e := echo.New() + + // We now register our petStore above as the handler for the interface + server.RegisterHandlers(e, petStore) + + log.Printf("Server listening on %s", net.JoinHostPort("0.0.0.0", *port)) + + // And we serve HTTP until the world ends. + log.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port))) +} diff --git a/experimental/examples/petstore-expanded/echo/server/petstore.go b/experimental/examples/petstore-expanded/echo/server/petstore.go new file mode 100644 index 0000000000..276030da81 --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/server/petstore.go @@ -0,0 +1,123 @@ +//go:build go1.22 + +package server + +import ( + "net/http" + "sync" + + "github.com/labstack/echo/v5" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(ctx *echo.Context, code int, message string) error { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + return ctx.JSON(code, petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(ctx *echo.Context, params FindPetsParams) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.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) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(ctx *echo.Context) error { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := ctx.Bind(&newPet); err != nil { + return sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + return ctx.JSON(http.StatusCreated, pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(ctx *echo.Context, id int64) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + return sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") + } + + return ctx.JSON(http.StatusOK, pet) +} + +// DeletePet deletes a pet by ID. +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, "Could not find pet with ID") + } + delete(p.Pets, id) + + return ctx.NoContent(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/echo/server/server.config.yaml b/experimental/examples/petstore-expanded/echo/server/server.config.yaml new file mode 100644 index 0000000000..16a0b6b82d --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: echo + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/echo/server/server.gen.go b/experimental/examples/petstore-expanded/echo/server/server.gen.go new file mode 100644 index 0000000000..da099a985f --- /dev/null +++ b/experimental/examples/petstore-expanded/echo/server/server.gen.go @@ -0,0 +1,977 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" + "github.com/labstack/echo/v5" +) + +// 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 +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(ctx *echo.Context, params FindPetsParams) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(ctx *echo.Context) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(ctx *echo.Context, id int64) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(ctx *echo.Context, id int64) error { + return ctx.NoContent(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// 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 = BindFormExplodeParam("tags", false, ctx.QueryParams(), ¶ms.Tags) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, ctx.QueryParams(), ¶ms.Limit) + 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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.FindPetByID(ctx, id) + return err +} + +// EchoRouter is an interface for echo.Echo and echo.Group. +type EchoRouter interface { + Add(method string, path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo + 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 +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router EchoRouter, si ServerInterface) { + RegisterHandlersWithBaseURL(router, si, "") +} + +// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. +func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { + + 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) +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/fiber/Makefile b/experimental/examples/petstore-expanded/fiber/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/fiber/go.mod b/experimental/examples/petstore-expanded/fiber/go.mod new file mode 100644 index 0000000000..aa60e0d81c --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/go.mod @@ -0,0 +1,31 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/fiber + +go 1.24.0 + +require ( + github.com/gofiber/fiber/v3 v3.0.0-beta.4 + github.com/google/uuid v1.6.0 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +require ( + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gofiber/schema v1.2.0 // indirect + github.com/gofiber/utils/v2 v2.0.0-beta.7 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/tinylib/msgp v1.2.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.58.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.33.0 // indirect +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/fiber/go.sum b/experimental/examples/petstore-expanded/fiber/go.sum new file mode 100644 index 0000000000..00a56bd56e --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/go.sum @@ -0,0 +1,51 @@ +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +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/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gofiber/fiber/v3 v3.0.0-beta.4 h1:KzDSavvhG7m81NIsmnu5l3ZDbVS4feCidl4xlIfu6V0= +github.com/gofiber/fiber/v3 v3.0.0-beta.4/go.mod h1:/WFUoHRkZEsGHyy2+fYcdqi109IVOFbVwxv1n1RU+kk= +github.com/gofiber/schema v1.2.0 h1:j+ZRrNnUa/0ZuWrn/6kAtAufEr4jCJ+JuTURAMxNSZg= +github.com/gofiber/schema v1.2.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c= +github.com/gofiber/utils/v2 v2.0.0-beta.7 h1:NnHFrRHvhrufPABdWajcKZejz9HnCWmT/asoxRsiEbQ= +github.com/gofiber/utils/v2 v2.0.0-beta.7/go.mod h1:J/M03s+HMdZdvhAeyh76xT72IfVqBzuz/OJkrMa7cwU= +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/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +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/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= +github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +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.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE= +github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw= +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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +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/experimental/examples/petstore-expanded/fiber/main.go b/experimental/examples/petstore-expanded/fiber/main.go new file mode 100644 index 0000000000..a429cc08f3 --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/main.go @@ -0,0 +1,35 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + + "github.com/gofiber/fiber/v3" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/fiber/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + app := fiber.New() + + // We now register our petStore above as the handler for the interface + server.RegisterHandlers(app, petStore) + + addr := net.JoinHostPort("0.0.0.0", *port) + log.Printf("Server listening on %s", addr) + + // And we serve HTTP until the world ends. + log.Fatal(app.Listen(addr)) +} diff --git a/experimental/examples/petstore-expanded/fiber/server/petstore.go b/experimental/examples/petstore-expanded/fiber/server/petstore.go new file mode 100644 index 0000000000..0692078618 --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/server/petstore.go @@ -0,0 +1,122 @@ +//go:build go1.22 + +package server + +import ( + "sync" + + "github.com/gofiber/fiber/v3" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(c fiber.Ctx, code int, message string) error { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + return c.Status(code).JSON(petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(c fiber.Ctx, params FindPetsParams) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.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 c.Status(fiber.StatusOK).JSON(result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(c fiber.Ctx) error { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := c.Bind().JSON(&newPet); err != nil { + return sendPetStoreError(c, fiber.StatusBadRequest, "Invalid format for NewPet") + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + return c.Status(fiber.StatusCreated).JSON(pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(c fiber.Ctx, id int64) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + return sendPetStoreError(c, fiber.StatusNotFound, "Could not find pet with ID") + } + + return c.Status(fiber.StatusOK).JSON(pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(c fiber.Ctx, id int64) error { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + return sendPetStoreError(c, fiber.StatusNotFound, "Could not find pet with ID") + } + delete(p.Pets, id) + + return c.SendStatus(fiber.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/fiber/server/server.config.yaml b/experimental/examples/petstore-expanded/fiber/server/server.config.yaml new file mode 100644 index 0000000000..1038e55a98 --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: fiber + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/fiber/server/server.gen.go b/experimental/examples/petstore-expanded/fiber/server/server.gen.go new file mode 100644 index 0000000000..a38d4cfb87 --- /dev/null +++ b/experimental/examples/petstore-expanded/fiber/server/server.gen.go @@ -0,0 +1,969 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/gofiber/fiber/v3" + "github.com/google/uuid" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(c fiber.Ctx, params FindPetsParams) error + // Creates a new pet + // (POST /pets) + AddPet(c fiber.Ctx) error + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(c fiber.Ctx, id int64) error + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(c fiber.Ctx, id int64) error +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(c fiber.Ctx, params FindPetsParams) error { + return c.SendStatus(fiber.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(c fiber.Ctx) error { + return c.SendStatus(fiber.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(c fiber.Ctx, id int64) error { + return c.SendStatus(fiber.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(c fiber.Ctx, id int64) error { + return c.SendStatus(fiber.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(c fiber.Ctx) error { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for query string: %s", err)) + } + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, query, ¶ms.Tags) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, query, ¶ms.Limit) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) + } + + return siw.Handler.FindPets(c, params) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(c fiber.Ctx) error { + + return siw.Handler.AddPet(c) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(c fiber.Ctx) error { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, c.Params("id"), &id) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + return siw.Handler.DeletePet(c, id) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(c fiber.Ctx) error { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, c.Params("id"), &id) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) + } + + return siw.Handler.FindPetByID(c, id) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []fiber.Handler +} + +// 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, + } + + for _, m := range options.Middlewares { + router.Use(m) + } + + router.Get(options.BaseURL+"/pets", wrapper.FindPets) + router.Post(options.BaseURL+"/pets", wrapper.AddPet) + router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet) + router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID) +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/generate.go b/experimental/examples/petstore-expanded/generate.go new file mode 100644 index 0000000000..b8a15f94ef --- /dev/null +++ b/experimental/examples/petstore-expanded/generate.go @@ -0,0 +1,11 @@ +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config models.config.yaml petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config stdhttp/server/server.config.yaml -output stdhttp/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config chi/server/server.config.yaml -output chi/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config echo-v4/server/server.config.yaml -output echo-v4/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config echo/server/server.config.yaml -output echo/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config gin/server/server.config.yaml -output gin/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config gorilla/server/server.config.yaml -output gorilla/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config fiber/server/server.config.yaml -output fiber/server/server.gen.go petstore-expanded.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config iris/server/server.config.yaml -output iris/server/server.gen.go petstore-expanded.yaml + +package petstore diff --git a/experimental/examples/petstore-expanded/gin/Makefile b/experimental/examples/petstore-expanded/gin/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/gin/go.mod b/experimental/examples/petstore-expanded/gin/go.mod new file mode 100644 index 0000000000..eed1c070da --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/go.mod @@ -0,0 +1,40 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gin + +go 1.24.0 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/google/uuid v1.6.0 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +require ( + 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/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.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/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.33.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/gin/go.sum b/experimental/examples/petstore-expanded/gin/go.sum new file mode 100644 index 0000000000..fa550cb75e --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/go.sum @@ -0,0 +1,92 @@ +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/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/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/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-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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +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/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/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/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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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/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/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= +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= +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/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/experimental/examples/petstore-expanded/gin/main.go b/experimental/examples/petstore-expanded/gin/main.go new file mode 100644 index 0000000000..91148c8846 --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/main.go @@ -0,0 +1,40 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gin/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + r := gin.Default() + + // We now register our petStore above as the handler for the interface + server.RegisterHandlers(r, petStore) + + s := &http.Server{ + Handler: r, + Addr: net.JoinHostPort("0.0.0.0", *port), + } + + log.Printf("Server listening on %s", s.Addr) + + // And we serve HTTP until the world ends. + log.Fatal(s.ListenAndServe()) +} diff --git a/experimental/examples/petstore-expanded/gin/server/petstore.go b/experimental/examples/petstore-expanded/gin/server/petstore.go new file mode 100644 index 0000000000..45f4801f25 --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/server/petstore.go @@ -0,0 +1,126 @@ +//go:build go1.22 + +package server + +import ( + "net/http" + "sync" + + "github.com/gin-gonic/gin" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(c *gin.Context, code int, message string) { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + c.JSON(code, petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(c *gin.Context, params FindPetsParams) { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.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 + } + } + } + + c.JSON(http.StatusOK, result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(c *gin.Context) { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := c.ShouldBindJSON(&newPet); err != nil { + sendPetStoreError(c, http.StatusBadRequest, "Invalid format for NewPet") + return + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + c.JSON(http.StatusCreated, pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(c *gin.Context, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + sendPetStoreError(c, http.StatusNotFound, "Could not find pet with ID") + return + } + + c.JSON(http.StatusOK, pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(c *gin.Context, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + sendPetStoreError(c, http.StatusNotFound, "Could not find pet with ID") + return + } + delete(p.Pets, id) + + c.Status(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/gin/server/server.config.yaml b/experimental/examples/petstore-expanded/gin/server/server.config.yaml new file mode 100644 index 0000000000..9b26a5e3b9 --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: gin + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/gin/server/server.gen.go b/experimental/examples/petstore-expanded/gin/server/server.gen.go new file mode 100644 index 0000000000..87d877c5c8 --- /dev/null +++ b/experimental/examples/petstore-expanded/gin/server/server.gen.go @@ -0,0 +1,1007 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(c *gin.Context, params FindPetsParams) + // Creates a new pet + // (POST /pets) + AddPet(c *gin.Context) + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(c *gin.Context, id int64) + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(c *gin.Context, id int64) +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(c *gin.Context, params FindPetsParams) { + c.Status(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(c *gin.Context) { + c.Status(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(c *gin.Context, id int64) { + c.Status(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(c *gin.Context, id int64) { + c.Status(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(c *gin.Context) + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, c.Request.URL.Query(), ¶ms.Tags) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter tags: %w", err), http.StatusBadRequest) + return + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, c.Request.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter limit: %w", err), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.FindPets(c, params) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) { + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.AddPet(c) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, c.Param("id"), &id) + 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.DeletePet(c, id) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, c.Param("id"), &id) + 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.FindPetByID(c, id) +} + +// 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+"/pets", wrapper.FindPets) + router.POST(options.BaseURL+"/pets", wrapper.AddPet) + router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet) + router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID) +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/gorilla/Makefile b/experimental/examples/petstore-expanded/gorilla/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/gorilla/go.mod b/experimental/examples/petstore-expanded/gorilla/go.mod new file mode 100644 index 0000000000..fa094711da --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/go.mod @@ -0,0 +1,11 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gorilla + +go 1.24.0 + +require ( + github.com/google/uuid v1.6.0 + github.com/gorilla/mux v1.8.1 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/gorilla/go.sum b/experimental/examples/petstore-expanded/gorilla/go.sum new file mode 100644 index 0000000000..c9af5271c5 --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/go.sum @@ -0,0 +1,4 @@ +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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= diff --git a/experimental/examples/petstore-expanded/gorilla/main.go b/experimental/examples/petstore-expanded/gorilla/main.go new file mode 100644 index 0000000000..1bde88bcca --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/main.go @@ -0,0 +1,40 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + "net/http" + + "github.com/gorilla/mux" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gorilla/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + r := mux.NewRouter() + + // We now register our petStore above as the handler for the interface + server.HandlerFromMux(petStore, r) + + s := &http.Server{ + Handler: r, + Addr: net.JoinHostPort("0.0.0.0", *port), + } + + log.Printf("Server listening on %s", s.Addr) + + // And we serve HTTP until the world ends. + log.Fatal(s.ListenAndServe()) +} diff --git a/experimental/examples/petstore-expanded/gorilla/server/petstore.go b/experimental/examples/petstore-expanded/gorilla/server/petstore.go new file mode 100644 index 0000000000..2f52c8e271 --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/server/petstore.go @@ -0,0 +1,135 @@ +//go:build go1.22 + +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" + + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(w http.ResponseWriter, code int, message string) { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.Pet + + for _, pet := range p.Pets { + if params.Tags != nil { + // If we have tags, filter pets by tag + for _, t := range *params.Tags { + if pet.Tag != nil && (*pet.Tag == t) { + result = append(result, pet) + } + } + } else { + // Add all pets if we're not filtering + result = append(result, pet) + } + + if params.Limit != nil { + l := int(*params.Limit) + if len(result) >= l { + // We're at the limit + break + } + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { + sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") + return + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + delete(p.Pets, id) + + w.WriteHeader(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml b/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml new file mode 100644 index 0000000000..5de1d21f15 --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: gorilla + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/gorilla/server/server.gen.go b/experimental/examples/petstore-expanded/gorilla/server/server.gen.go new file mode 100644 index 0000000000..957f88149e --- /dev/null +++ b/experimental/examples/petstore-expanded/gorilla/server/server.gen.go @@ -0,0 +1,1035 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" + "github.com/gorilla/mux" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) + // Creates a new pet + // (POST /pets) + AddPet(w http.ResponseWriter, r *http.Request) + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(w http.ResponseWriter, r *http.Request, id int64) + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(w http.ResponseWriter, r *http.Request, id int64) +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { + w.WriteHeader(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) + return + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPets(w, r, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.AddPet(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { + var err error + + pathParams := mux.Vars(r) + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, pathParams["id"], &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeletePet(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { + var err error + + pathParams := mux.Vars(r) + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, pathParams["id"], &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPetByID(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, GorillaServerOptions{}) +} + +// GorillaServerOptions configures the Gorilla server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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+"/pets", wrapper.FindPets).Methods("GET") + r.HandleFunc(options.BaseURL+"/pets", wrapper.AddPet).Methods("POST") + r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.DeletePet).Methods("DELETE") + r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.FindPetByID).Methods("GET") + return r +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/iris/Makefile b/experimental/examples/petstore-expanded/iris/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/iris/go.mod b/experimental/examples/petstore-expanded/iris/go.mod new file mode 100644 index 0000000000..b13819f2a5 --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/go.mod @@ -0,0 +1,55 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/iris + +go 1.24.0 + +require ( + github.com/google/uuid v1.6.0 + github.com/kataras/iris/v12 v12.2.11 + github.com/oapi-codegen/oapi-codegen/experimental v0.0.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/Joker/jade v1.1.3 // indirect + github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/flosch/pongo2/v4 v4.0.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/iris-contrib/schema v0.0.6 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kataras/blocks v0.0.8 // 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.7 // indirect + github.com/mailgun/raymond/v2 v2.0.48 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/microcosm-cc/bluemonday v1.0.26 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/schollz/closestmatch v2.1.0+incompatible // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/tdewolff/minify/v2 v2.20.19 // indirect + github.com/tdewolff/parse/v2 v2.7.12 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/yosssi/ace v0.0.5 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.33.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/iris/go.sum b/experimental/examples/petstore-expanded/iris/go.sum new file mode 100644 index 0000000000..a06439c9fc --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/go.sum @@ -0,0 +1,178 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= +github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= +github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +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-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= +github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +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= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= +github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= +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.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= +github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= +github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= +github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= +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/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/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/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.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +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/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.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/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= +moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs= +moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= diff --git a/experimental/examples/petstore-expanded/iris/main.go b/experimental/examples/petstore-expanded/iris/main.go new file mode 100644 index 0000000000..48d035a84d --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/main.go @@ -0,0 +1,35 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + + "github.com/kataras/iris/v12" + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/iris/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + app := iris.New() + + // We now register our petStore above as the handler for the interface + server.RegisterHandlers(app, petStore) + + addr := net.JoinHostPort("0.0.0.0", *port) + log.Printf("Server listening on %s", addr) + + // And we serve HTTP until the world ends. + log.Fatal(app.Listen(addr)) +} diff --git a/experimental/examples/petstore-expanded/iris/server/petstore.go b/experimental/examples/petstore-expanded/iris/server/petstore.go new file mode 100644 index 0000000000..cab647706c --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/server/petstore.go @@ -0,0 +1,130 @@ +//go:build go1.22 + +package server + +import ( + "net/http" + "sync" + + "github.com/kataras/iris/v12" + petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" +) + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]petstore.Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]petstore.Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(ctx iris.Context, code int, message string) { + petErr := petstore.Error{ + Code: int32(code), + Message: message, + } + ctx.StatusCode(code) + _ = ctx.JSON(petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(ctx iris.Context, params FindPetsParams) { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []petstore.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 + } + } + } + + ctx.StatusCode(http.StatusOK) + _ = ctx.JSON(result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(ctx iris.Context) { + // We expect a NewPet object in the request body. + var newPet petstore.NewPet + if err := ctx.ReadJSON(&newPet); err != nil { + sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") + return + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet petstore.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 Pet + ctx.StatusCode(http.StatusCreated) + _ = ctx.JSON(pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(ctx iris.Context, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") + return + } + + ctx.StatusCode(http.StatusOK) + _ = ctx.JSON(pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(ctx iris.Context, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") + return + } + delete(p.Pets, id) + + ctx.StatusCode(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/iris/server/server.config.yaml b/experimental/examples/petstore-expanded/iris/server/server.config.yaml new file mode 100644 index 0000000000..443b44a84b --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/server/server.config.yaml @@ -0,0 +1,6 @@ +package: server +generation: + server: iris + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/iris/server/server.gen.go b/experimental/examples/petstore-expanded/iris/server/server.gen.go new file mode 100644 index 0000000000..1c59478225 --- /dev/null +++ b/experimental/examples/petstore-expanded/iris/server/server.gen.go @@ -0,0 +1,973 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" + "github.com/kataras/iris/v12" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(ctx iris.Context, params FindPetsParams) + // Creates a new pet + // (POST /pets) + AddPet(ctx iris.Context) + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(ctx iris.Context, id int64) + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(ctx iris.Context, id int64) +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +// Returns all pets +// (GET /pets) +func (_ Unimplemented) FindPets(ctx iris.Context, params FindPetsParams) { + ctx.StatusCode(http.StatusNotImplemented) +} + +// Creates a new pet +// (POST /pets) +func (_ Unimplemented) AddPet(ctx iris.Context) { + ctx.StatusCode(http.StatusNotImplemented) +} + +// Deletes a pet by ID +// (DELETE /pets/{id}) +func (_ Unimplemented) DeletePet(ctx iris.Context, id int64) { + ctx.StatusCode(http.StatusNotImplemented) +} + +// Returns a pet by ID +// (GET /pets/{id}) +func (_ Unimplemented) FindPetByID(ctx iris.Context, id int64) { + ctx.StatusCode(http.StatusNotImplemented) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts iris contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +// FindPets converts iris context to params. +func (w *ServerInterfaceWrapper) FindPets(ctx iris.Context) { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, ctx.Request().URL.Query(), ¶ms.Tags) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter tags: %s", err)) + return + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, ctx.Request().URL.Query(), ¶ms.Limit) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter limit: %s", err)) + return + } + + // Invoke the callback with all the unmarshaled arguments + w.Handler.FindPets(ctx, params) +} + +// AddPet converts iris context to params. +func (w *ServerInterfaceWrapper) AddPet(ctx iris.Context) { + + // Invoke the callback with all the unmarshaled arguments + w.Handler.AddPet(ctx) +} + +// DeletePet converts iris context to params. +func (w *ServerInterfaceWrapper) DeletePet(ctx iris.Context) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, ctx.Params().Get("id"), &id) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter id: %s", err)) + return + } + + // Invoke the callback with all the unmarshaled arguments + w.Handler.DeletePet(ctx, id) +} + +// FindPetByID converts iris context to params. +func (w *ServerInterfaceWrapper) FindPetByID(ctx iris.Context) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, ctx.Params().Get("id"), &id) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter id: %s", err)) + return + } + + // Invoke the callback with all the unmarshaled arguments + w.Handler.FindPetByID(ctx, id) +} + +// IrisServerOptions is the option for iris server. +type IrisServerOptions struct { + BaseURL string + Middlewares []iris.Handler +} + +// 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+"/pets", wrapper.FindPets) + router.Post(options.BaseURL+"/pets", wrapper.AddPet) + router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet) + router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID) + router.Build() +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/petstore-expanded/models.config.yaml b/experimental/examples/petstore-expanded/models.config.yaml new file mode 100644 index 0000000000..47d99a649f --- /dev/null +++ b/experimental/examples/petstore-expanded/models.config.yaml @@ -0,0 +1,2 @@ +package: petstore +output: petstore.gen.go diff --git a/experimental/examples/petstore-expanded/petstore-expanded.yaml b/experimental/examples/petstore-expanded/petstore-expanded.yaml new file mode 100644 index 0000000000..f9f84f2854 --- /dev/null +++ b/experimental/examples/petstore-expanded/petstore-expanded.yaml @@ -0,0 +1,164 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification + termsOfService: https://swagger.io/terms/ + contact: + name: Swagger API Team + email: apiteam@swagger.io + url: https://swagger.io + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: https://petstore.swagger.io/api +paths: + /pets: + get: + summary: Returns all pets + description: | + Returns all pets from the system that the user has access to + Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. + + Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. + operationId: findPets + parameters: + - name: tags + in: query + description: tags to filter by + required: false + style: form + schema: + type: array + items: + type: string + - name: limit + in: query + description: maximum number of results to return + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: pet response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Creates a new pet + description: Creates a new pet in the store. Duplicates are allowed + operationId: addPet + requestBody: + description: Pet to add to the store + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NewPet' + responses: + '200': + description: pet response + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /pets/{id}: + get: + summary: Returns a pet by ID + description: Returns a pet based on a single ID + operationId: findPetByID + parameters: + - name: id + in: path + description: ID of pet to fetch + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: pet response + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Deletes a pet by ID + description: deletes a single pet based on the ID supplied + operationId: deletePet + parameters: + - name: id + in: path + description: ID of pet to delete + required: true + schema: + type: integer + format: int64 + responses: + '204': + description: pet deleted + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +components: + schemas: + Pet: + allOf: + - $ref: '#/components/schemas/NewPet' + - required: + - id + properties: + id: + type: integer + format: int64 + description: Unique id of the pet + + NewPet: + required: + - name + properties: + name: + type: string + description: Name of the pet + tag: + type: string + description: Type of the pet + + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message diff --git a/experimental/examples/petstore-expanded/petstore.gen.go b/experimental/examples/petstore-expanded/petstore.gen.go new file mode 100644 index 0000000000..4149df2b00 --- /dev/null +++ b/experimental/examples/petstore-expanded/petstore.gen.go @@ -0,0 +1,117 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package petstore + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Pet +type Pet struct { + Name string `json:"name" form:"name"` // Name of the pet + Tag *string `json:"tag,omitempty" form:"tag,omitempty"` // Type of the pet + ID int64 `json:"id" form:"id"` // Unique id of the pet +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Pet) ApplyDefaults() { +} + +// #/components/schemas/NewPet +type NewPet struct { + Name string `json:"name" form:"name"` // Name of the pet + Tag *string `json:"tag,omitempty" form:"tag,omitempty"` // Type of the pet +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NewPet) ApplyDefaults() { +} + +// #/components/schemas/Error +type Error struct { + Code int32 `json:"code" form:"code"` // Error code + Message string `json:"message" form:"message"` // Error message +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Error) ApplyDefaults() { +} + +// #/paths//pets/get/responses/200/content/application/json/schema +type FindPetsJSONResponse = []Pet + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/+xXXW9byQ19168gtgXyoly5yaIPemo2TgED3cStd/tOz6UkLubLQ44coe1/Lzj3Srqy", + "ZG+CYvuF9YMNz3A4hzyHHN6UKWLmJXzztrvqrr6ZcVyl5QxgS0U4xSX8ztZnAMrqaQl3j7heU4FbUtFU", + "aAbQk7jCWZv5OxAM2RO8u70B3aBCFRJAyOMBQAGMQJ8HM03QU0hRtKASrAi1FhLgCLoh+JQpmqe33RVI", + "Jscrdmg3GSIqQT6t7qhs2dESNqpZlouFDBA7TotmspgBuBQVnVpkABHDJBJz/wNhaFsUkP0SMLMShj8c", + "XbXdWvyla2YAnh1Foan/dxndhuBNy96Ts4+Pjx22/S6V9WI8LYs/3bz/8PHuw+s33VW30eBnQsWYML+v", + "T13s89lNwsXMs4y6afbNYgC0pjFyAKkhYNkt4S+ktUQB9L5xM+6fkPn3cRHOrGFVUmgMyU6UwkC1/V+F", + "CmyMZOdIBDQdnHzEAEK9kdFzoKg1AIl28D2So4gCSiGnAoJrVmUBwcwU5xDJQdmk6KqAUJgYsAIG0g7e", + "USSMgArrglvuEbCuK80BHTC66rkd7eB9LXjPWguknhP4VCjMIZWIhYDWpECeRnSR3BxcLVIFuAdPTqt0", + "cF1ZIDBoLZllDrn6LUcsdheVZLHPQTk67mtU2GLhKvBTFU0d3ETYoIONgUARguxRCaFnpzVYOm6ikikT", + "FbDnzOI4rgGjWjTH2D2vq8dD5HmDhbTgPolmDyF5EmUCDplKz5apv/IWwxAQen6oGKBntMwUFHiw2Lbk", + "WSGmCJqKpmIp4RXF/nB7B7cFSSiqwaTI4QigloiwTb5qRoUtRYpogIfk2q+AtZiPm3j0vKIyZn2Fjj3L", + "ySXtBvs1P/LrQFKPnozYfm55dFRQLTD728FdlUyxZ8uyRxNPn3wqc1OgkFMTdYuyScWinsOWNuyqR+Co", + "VPoawPM9ldTB96ncM1BlCamf0mDbTdgeHUfGbnaQ/B31jY8qsCKToE/3qbRjlI66KVVLDV2rkIDN7UgB", + "i58D1ZOaGYgHX02NptEObjco5P1QHpnKeLwlu5FMCiusju/rkHbc32N20/Nb8iOBvKVScH56tVULcD8/", + "lGPk+00HPypk8p6ikjxUgpykktXTvpS6lgrc14KV3j6je0/7sFo+5w3IQRyxRgdaWNRigS0rUgd/rOII", + "SFtP6CsfasH6hTjyVLjBGVS8PxBMMxWbhFwNghECri1k8iNbHfy5DkdD8sbbwB7VQUFHKPNDCwKszkpl", + "sBxFOoQ9SmRsNYeaNMkYwcBxfoQylm9k4T1gMQyOtfZsUEUQqu7VNhI53HSStHZfB7dTYlrmRoy5kHIN", + "k/41iKbOJyq3BtyNek7Z6opTvOmXsOLY3x4fjozFsjA+VsPP6/EpVFzLYRGA4xIeKpXdZO3k3TF7mwxW", + "7JUK3E8NCz1ULmQA0AtNdkR3NqGsUgnTVbehgMvJCoDuMi0BS8HdyTorBTk13RuLFo7rs8g8B9avCS3g", + "Zw72stRwTwXSCgpJ9driLe2V/bJgnw2Lh9fjZMdygtr23r6Z7X1LtjY4CfjVm6urV8vnoGfSw6GJjY1W", + "FPUUCubsx0lt8ZOk+DSpl+C/xMyz7NjPbwutlvDqNwuXQk6RospiuEAWt6SvZsdwVli9PhthjfQ527tg", + "D0hJ5ZeK8iXAH+ziAXJOcj63vS+E2ibqSI/GyaXB7cxoP08PIyNc1wG4mdhI7n16pP5SlWNvRT47ypFE", + "v0v9bjm7mMFbUhMy9r39Odw4Oxe0lnpcvpDdl3N7ObMv5fUjPU608F8p/v9PHbfvkMXfuP/HF3yMtDzf", + "7+Dm+pKsn5ihPaA2vYFwXHs6nrr0UH23O2y/9FZx/6Sd2wfVc4m+ubYOngfRr0jd5mLzPtH6v9C7f//t", + "r/L997fhnjwpnWn2ui3/rGb7g9ko0hPpWoe8uQapFsLlDjw4ODbhX0a8wy3/SfV++7J6B4D9/6KIjjt2", + "fNwcPN0emyF6/2k1pfTLXzOzPvB1gvD1qSRyMWkp05M5ivvLU+8lRi9zepGDH2P7WuPehGZSt3GlHRjw", + "L2dPtPZE0LPnUTe9z35mSn8C5yMGmiI5nMX117r6YZfpLKhG90sxudTT5N9AIrh+KUo7cA7tnJVL8/0Z", + "5gbvFMOI4GujHzzt4f8zAAD//6ZcwVZEFgAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/examples/petstore-expanded/stdhttp/Makefile b/experimental/examples/petstore-expanded/stdhttp/Makefile new file mode 100644 index 0000000000..42389f4137 --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/Makefile @@ -0,0 +1,35 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/stdhttp/go.mod b/experimental/examples/petstore-expanded/stdhttp/go.mod new file mode 100644 index 0000000000..e211ad75fb --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/go.mod @@ -0,0 +1,7 @@ +module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/stdhttp + +go 1.24.0 + +require github.com/google/uuid v1.6.0 + +replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/stdhttp/go.sum b/experimental/examples/petstore-expanded/stdhttp/go.sum new file mode 100644 index 0000000000..7790d7c3e0 --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/go.sum @@ -0,0 +1,2 @@ +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= diff --git a/experimental/examples/petstore-expanded/stdhttp/main.go b/experimental/examples/petstore-expanded/stdhttp/main.go new file mode 100644 index 0000000000..9f438a128d --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/main.go @@ -0,0 +1,39 @@ +//go:build go1.22 + +// This is an example of implementing the Pet Store from the OpenAPI documentation +// found at: +// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml + +package main + +import ( + "flag" + "log" + "net" + "net/http" + + "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/stdhttp/server" +) + +func main() { + port := flag.String("port", "8080", "Port for test HTTP server") + flag.Parse() + + // Create an instance of our handler which satisfies the generated interface + petStore := server.NewPetStore() + + r := http.NewServeMux() + + // We now register our petStore above as the handler for the interface + server.HandlerFromMux(petStore, r) + + s := &http.Server{ + Handler: r, + Addr: net.JoinHostPort("0.0.0.0", *port), + } + + log.Printf("Server listening on %s", s.Addr) + + // And we serve HTTP until the world ends. + log.Fatal(s.ListenAndServe()) +} diff --git a/experimental/examples/petstore-expanded/stdhttp/server/petstore.go b/experimental/examples/petstore-expanded/stdhttp/server/petstore.go new file mode 100644 index 0000000000..f05a50f1e6 --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/server/petstore.go @@ -0,0 +1,163 @@ +//go:build go1.22 + +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" +) + +// 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"` +} + +// 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"` +} + +// Error defines model for Error. +type Error struct { + // Code Error code + Code int32 `json:"code"` + + // Message Error message + Message string `json:"message"` +} + +// PetStore implements the ServerInterface. +type PetStore struct { + Pets map[int64]Pet + NextId int64 + Lock sync.Mutex +} + +// Make sure we conform to ServerInterface +var _ ServerInterface = (*PetStore)(nil) + +// NewPetStore creates a new PetStore. +func NewPetStore() *PetStore { + return &PetStore{ + Pets: make(map[int64]Pet), + NextId: 1000, + } +} + +// sendPetStoreError wraps sending of an error in the Error format. +func sendPetStoreError(w http.ResponseWriter, code int, message string) { + petErr := Error{ + Code: int32(code), + Message: message, + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(petErr) +} + +// FindPets returns all pets, optionally filtered by tags and limited. +func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { + p.Lock.Lock() + defer p.Lock.Unlock() + + var result []Pet + + for _, pet := range p.Pets { + if params.Tags != nil { + // If we have tags, filter pets by tag + for _, t := range *params.Tags { + if pet.Tag != nil && (*pet.Tag == t) { + result = append(result, pet) + } + } + } else { + // Add all pets if we're not filtering + result = append(result, pet) + } + + if params.Limit != nil { + l := int(*params.Limit) + if len(result) >= l { + // We're at the limit + break + } + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(result) +} + +// AddPet creates a new pet. +func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { + // We expect a NewPet object in the request body. + var newPet NewPet + if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { + sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") + return + } + + // We now have a pet, let's add it to our "database". + p.Lock.Lock() + defer p.Lock.Unlock() + + // We handle pets, not NewPets, which have an additional ID field + var pet Pet + pet.Name = newPet.Name + pet.Tag = newPet.Tag + pet.Id = p.NextId + p.NextId++ + + // Insert into map + p.Pets[pet.Id] = pet + + // Now, we have to return the Pet + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(pet) +} + +// FindPetByID returns a pet by ID. +func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + pet, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(pet) +} + +// DeletePet deletes a pet by ID. +func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { + p.Lock.Lock() + defer p.Lock.Unlock() + + _, found := p.Pets[id] + if !found { + sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) + return + } + delete(p.Pets, id) + + w.WriteHeader(http.StatusNoContent) +} diff --git a/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml b/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml new file mode 100644 index 0000000000..4bb9655ead --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml @@ -0,0 +1,7 @@ +package: server +output: server.gen.go +generation: + server: std-http + models-package: + path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded + alias: petstore diff --git a/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go b/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go new file mode 100644 index 0000000000..a65e2e57e1 --- /dev/null +++ b/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go @@ -0,0 +1,1009 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package server + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Returns all pets + // (GET /pets) + FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) + // Creates a new pet + // (POST /pets) + AddPet(w http.ResponseWriter, r *http.Request) + // Deletes a pet by ID + // (DELETE /pets/{id}) + DeletePet(w http.ResponseWriter, r *http.Request, id int64) + // Returns a pet by ID + // (GET /pets/{id}) + FindPetByID(w http.ResponseWriter, r *http.Request, id int64) +} + +// FindPetsParams defines parameters for FindPets. +type FindPetsParams struct { + // tags (optional) + Tags *[]string `form:"tags" json:"tags"` + // limit (optional) + Limit *int32 `form:"limit" json:"limit"` +} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +// FindPets operation middleware +func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params FindPetsParams + + // ------------- Optional query parameter "tags" ------------- + err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) + return + } + + // ------------- Optional query parameter "limit" ------------- + err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPets(w, r, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// AddPet operation middleware +func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.AddPet(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeletePet operation middleware +func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeletePet(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// FindPetByID operation middleware +func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "id" ------------- + var id int64 + + err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.FindPetByID(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +// StdHTTPServerOptions configures the StdHTTP server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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("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) + return m +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/examples/webhook/client/main.go b/experimental/examples/webhook/client/main.go new file mode 100644 index 0000000000..2d12c19acc --- /dev/null +++ b/experimental/examples/webhook/client/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "flag" + "fmt" + "log" + "net" + "net/http" + "time" + + "github.com/google/uuid" + + doorbadge "github.com/oapi-codegen/oapi-codegen/experimental/examples/webhook" +) + +// WebhookReceiver implements doorbadge.WebhookReceiverInterface. +type WebhookReceiver struct{} + +var _ doorbadge.WebhookReceiverInterface = (*WebhookReceiver)(nil) + +func (wr *WebhookReceiver) HandleEnterEventWebhook(w http.ResponseWriter, r *http.Request) { + var person doorbadge.Person + if err := json.NewDecoder(r.Body).Decode(&person); err != nil { + log.Printf("Error decoding enter event: %v", err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + log.Printf("ENTER: %s", person.Name) + w.WriteHeader(http.StatusOK) +} + +func (wr *WebhookReceiver) HandleExitEventWebhook(w http.ResponseWriter, r *http.Request) { + var person doorbadge.Person + if err := json.NewDecoder(r.Body).Decode(&person); err != nil { + log.Printf("Error decoding exit event: %v", err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + log.Printf("EXIT: %s", person.Name) + w.WriteHeader(http.StatusOK) +} + +func registerWebhook(client *http.Client, serverAddr, kind, url string) (uuid.UUID, error) { + body, err := json.Marshal(doorbadge.WebhookRegistration{URL: url}) + if err != nil { + return uuid.UUID{}, err + } + + resp, err := client.Post( + serverAddr+"/api/webhook/"+kind, + "application/json", + bytes.NewReader(body), + ) + if err != nil { + return uuid.UUID{}, err + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusCreated { + return uuid.UUID{}, fmt.Errorf("unexpected status %d", resp.StatusCode) + } + + var regResp doorbadge.WebhookRegistrationResponse + if err := json.NewDecoder(resp.Body).Decode(®Resp); err != nil { + return uuid.UUID{}, err + } + return regResp.ID, nil +} + +func deregisterWebhook(client *http.Client, serverAddr string, id uuid.UUID) error { + req, err := http.NewRequest(http.MethodDelete, serverAddr+"/api/webhook/"+id.String(), nil) + if err != nil { + return err + } + resp, err := client.Do(req) + if err != nil { + return err + } + _ = resp.Body.Close() + return nil +} + +func main() { + serverAddr := flag.String("server", "http://localhost:8080", "Badge reader server address") + duration := flag.Duration("duration", 30*time.Second, "How long to listen for events") + flag.Parse() + + // Start the webhook receiver on an ephemeral port. + receiver := &WebhookReceiver{} + + mux := http.NewServeMux() + mux.Handle("POST /enter", doorbadge.EnterEventWebhookHandler(receiver, nil)) + mux.Handle("POST /exit", doorbadge.ExitEventWebhookHandler(receiver, nil)) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatalf("Failed to listen: %v", err) + } + callbackPort := listener.Addr().(*net.TCPAddr).Port + baseURL := fmt.Sprintf("http://localhost:%d", callbackPort) + log.Printf("Webhook receiver listening on port %d", callbackPort) + + srv := &http.Server{Handler: mux} + go func() { + if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed { + log.Printf("Webhook server stopped: %v", err) + } + }() + + // Register webhooks for both event kinds. + client := &http.Client{} + + kinds := [2]string{"enterEvent", "exitEvent"} + urls := [2]string{baseURL + "/enter", baseURL + "/exit"} + var registrationIDs [2]uuid.UUID + + for i, kind := range kinds { + id, err := registerWebhook(client, *serverAddr, kind, urls[i]) + if err != nil { + log.Fatalf("Failed to register %s webhook: %v", kind, err) + } + registrationIDs[i] = id + log.Printf("Registered %s webhook: id=%s url=%s", kind, id, urls[i]) + } + + log.Printf("Listening for events for %s...", *duration) + + // Wait for the specified duration. + time.Sleep(*duration) + + // Deregister webhooks cleanly. + log.Printf("Duration elapsed, deregistering webhooks...") + for i, id := range registrationIDs { + if err := deregisterWebhook(client, *serverAddr, id); err != nil { + log.Printf("Failed to deregister %s webhook: %v", kinds[i], err) + continue + } + log.Printf("Deregistered %s webhook: id=%s", kinds[i], id) + } + + // Shut down the local webhook server. + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + _ = srv.Shutdown(ctx) + + log.Printf("Done!") +} diff --git a/experimental/examples/webhook/config.yaml b/experimental/examples/webhook/config.yaml new file mode 100644 index 0000000000..6a95d87ee1 --- /dev/null +++ b/experimental/examples/webhook/config.yaml @@ -0,0 +1,6 @@ +package: doorbadge +output: doorbadge.gen.go +generation: + webhook-initiator: true + webhook-receiver: true + server: std-http diff --git a/experimental/examples/webhook/doc.go b/experimental/examples/webhook/doc.go new file mode 100644 index 0000000000..ee6d3b6920 --- /dev/null +++ b/experimental/examples/webhook/doc.go @@ -0,0 +1,13 @@ +//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config config.yaml door-badge-reader.yaml + +// Package doorbadge provides an example of OpenAPI 3.1 webhooks. +// A door badge reader server generates random enter/exit events and +// notifies registered webhook listeners. +// +// You can run the example by running these two commands in parallel: +// +// go run ./server --port 8080 +// go run ./client --server http://localhost:8080 +// +// You can run multiple clients and they will all get the notifications +package doorbadge diff --git a/experimental/examples/webhook/door-badge-reader.yaml b/experimental/examples/webhook/door-badge-reader.yaml new file mode 100644 index 0000000000..ac37ce40dd --- /dev/null +++ b/experimental/examples/webhook/door-badge-reader.yaml @@ -0,0 +1,139 @@ +openapi: "3.1.0" +info: + version: 1.0.0 + title: Door Badge Reader + description: | + A door badge reader service that demonstrates OpenAPI 3.1 webhooks. + Clients register for enterEvent and exitEvent webhooks. The server + randomly generates badge events and notifies all registered listeners. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +paths: + /api/webhook/{kind}: + post: + summary: Register a webhook + description: | + Registers a webhook for the given event kind. The server will POST + to the provided URL whenever an event of that kind occurs. + operationId: RegisterWebhook + parameters: + - name: kind + in: path + required: true + schema: + type: string + enum: + - enterEvent + - exitEvent + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/WebhookRegistration' + responses: + '201': + description: Webhook registered + content: + application/json: + schema: + $ref: '#/components/schemas/WebhookRegistrationResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /api/webhook/{id}: + delete: + summary: Deregister a webhook + description: Removes a previously registered webhook by its ID. + operationId: DeregisterWebhook + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '204': + description: Webhook deregistered + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +webhooks: + enterEvent: + post: + summary: Person entered the building + operationId: EnterEvent + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Person' + responses: + '200': + description: Event received + exitEvent: + post: + summary: Person exited the building + operationId: ExitEvent + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Person' + responses: + '200': + description: Event received +components: + schemas: + WebhookRegistration: + type: object + required: + - url + properties: + url: + type: string + format: uri + description: URL to receive webhook events + + WebhookRegistrationResponse: + type: object + required: + - id + properties: + id: + type: string + format: uuid + description: Unique identifier for this webhook registration + + Person: + type: object + required: + - name + properties: + name: + type: string + description: Name of the person who badged in or out + + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message diff --git a/experimental/examples/webhook/doorbadge.gen.go b/experimental/examples/webhook/doorbadge.gen.go new file mode 100644 index 0000000000..702d74db62 --- /dev/null +++ b/experimental/examples/webhook/doorbadge.gen.go @@ -0,0 +1,1069 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package doorbadge + +import ( + "bytes" + "compress/gzip" + "context" + "encoding" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/google/uuid" +) + +// #/components/schemas/WebhookRegistration +type WebhookRegistration struct { + URL string `json:"url" form:"url"` // URL to receive webhook events +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *WebhookRegistration) ApplyDefaults() { +} + +// #/components/schemas/WebhookRegistrationResponse +type WebhookRegistrationResponse struct { + ID UUID `json:"id" form:"id"` // Unique identifier for this webhook registration +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *WebhookRegistrationResponse) ApplyDefaults() { +} + +// #/components/schemas/Person +type Person struct { + Name string `json:"name" form:"name"` // Name of the person who badged in or out +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Person) ApplyDefaults() { +} + +// #/components/schemas/Error +type Error struct { + Code int32 `json:"code" form:"code"` // Error code + Message string `json:"message" form:"message"` // Error message +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Error) ApplyDefaults() { +} + +// #/paths//api/webhook/{kind}/post/parameters/0/schema +type PostAPIWebhookKindParameter string + +const ( + PostAPIWebhookKindParameter_enterEvent PostAPIWebhookKindParameter = "enterEvent" + PostAPIWebhookKindParameter_exitEvent PostAPIWebhookKindParameter = "exitEvent" +) + +type UUID = uuid.UUID + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/9RWTY/bNhC961cM0gI+RfLu9qTbJuvDAkGycFL0TItjaxKJZIaUvEbb/16Q1GdX3l0D", + "RZv6ZEnDmfceh4+jDSphKIc3N+lVun6TkNrrPAFokS1plcNVuk7XCYAjV2EOd1ozvBPygLBFIZETAIm2", + "YDIuxP+RAADcgvSBuxDIIRAscksFgiuFA4m1VtaxcGjhk0F1+3APN+kVHHFXav3NpiHP+4pQOQuMB7IO", + "GfaaAZVD3rSoHAglAR/JxadhLXwpMdQL+ABYKKnr6gQHVBhrRmjYhvQ+jdKO9oQWRFUN9VBC5f8o5ICo", + "ogKVxTxkVaLGHG6NKEqE66ASQMNVDqVzxuZZdjweUxG+p5oPWbfaZh/u328+ft68vU7XaenqKjHCldZn", + "zYShrOOR/f6NlPwzFjPauvgPwDZ1LfiUw7aXRfTcu4iFLfG/Pt6OC4KirkQ4UIsqCgK+7lREOFJVwcOn", + "z1+GVE6HVYZ1SxIl/Lr9AMcSFfpw0SfS+7jdPiHoomi421gAbfxOkFb3ciTy24yFESxq9Hjzoe7bTnaf", + "cXgJQCoHL+LkFeP3hhhlDo4bnHywRYm1yCdvANzJYA7WManD7AOqpp6HegxjCz791LdjMsJA695peRrz", + "nMFWaOVQuWk9YUxFRRAq+2q1mmNZogLwM+M+h9VPWaFro5Vv8SxG2qxTOAoeN2A1ILVG+/4c862u11er", + "afpZY3W5JqdlErnA5SU25/hczGjbMVklI+69aCp3lkqj8NFg4VACMmv+L4hsfOHVExOg3gIkVujwiQnc", + "Ib/KBrZY69b7GxjGlnRjq9PU6HpD2J2AnIX7u8WTOlZ7/Vmlf+Wk7jXXwuXQNEO95Y7+5eWOlrjQ0/+j", + "HupvQr949KpnbpIHZKtVjEUZrH3XUCVHkWddsPm7//1gLhfpPG9s6/NtEMcJxgKpDQ0wmPorJHwk9xoF", + "f+xr4p8VcCzgV3Q14uIF9+6zxpOud1+xmKoUBJl4TMNV70HsJXY0xennseRF9xi8g+kcJT/gON1zGtwy", + "TpDJOS79TXQhp8HBliiRvIRRM3PfOSVF3xsEkqjC7MvdMEh2oMcTLpFk7IwL+fh74BlG4Zp4mdMM/EdR", + "Y5wvEUw8esdSx7leAinQDLpxEXSwxQsxF1ri5LFGa8XhORZ+wVMWpBwekBe2hpS7uT57gjziOYYOwaVC", + "xUw9/L8CAAD//+XREy3yDQAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Deregister a webhook + // (DELETE /api/webhook/{id}) + DeregisterWebhook(w http.ResponseWriter, r *http.Request, id uuid.UUID) + // Register a webhook + // (POST /api/webhook/{kind}) + RegisterWebhook(w http.ResponseWriter, r *http.Request, kind string) +} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +// DeregisterWebhook operation middleware +func (siw *ServerInterfaceWrapper) DeregisterWebhook(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "id" ------------- + var id uuid.UUID + + err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) + 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.DeregisterWebhook(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// RegisterWebhook operation middleware +func (siw *ServerInterfaceWrapper) RegisterWebhook(w http.ResponseWriter, r *http.Request) { + var err error + + // ------------- Path parameter "kind" ------------- + var kind string + + err = BindSimpleParam("kind", ParamLocationPath, r.PathValue("kind"), &kind) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "kind", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RegisterWebhook(w, r, kind) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +// StdHTTPServerOptions configures the StdHTTP server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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("DELETE "+options.BaseURL+"/api/webhook/{id}", wrapper.DeregisterWebhook) + m.HandleFunc("POST "+options.BaseURL+"/api/webhook/{kind}", wrapper.RegisterWebhook) + return m +} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +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) +} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} + +type EnterEventJSONRequestBody = Person + +type ExitEventJSONRequestBody = Person + +// RequestEditorFn is the function signature for the RequestEditor callback function. +// It may already be defined if client code is also generated; this is a compatible redeclaration. +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// HttpRequestDoer performs HTTP requests. +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// WebhookInitiator sends webhook requests to target URLs. +// Unlike Client, it has no stored base URL — the full target URL is provided per-call. +type WebhookInitiator struct { + // 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 +} + +// WebhookInitiatorOption allows setting custom parameters during construction. +type WebhookInitiatorOption func(*WebhookInitiator) error + +// NewWebhookInitiator creates a new WebhookInitiator with reasonable defaults. +func NewWebhookInitiator(opts ...WebhookInitiatorOption) (*WebhookInitiator, error) { + initiator := WebhookInitiator{} + for _, o := range opts { + if err := o(&initiator); err != nil { + return nil, err + } + } + if initiator.Client == nil { + initiator.Client = &http.Client{} + } + return &initiator, nil +} + +// WithWebhookHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithWebhookHTTPClient(doer HttpRequestDoer) WebhookInitiatorOption { + return func(p *WebhookInitiator) error { + p.Client = doer + return nil + } +} + +// WithWebhookRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithWebhookRequestEditorFn(fn RequestEditorFn) WebhookInitiatorOption { + return func(p *WebhookInitiator) error { + p.RequestEditors = append(p.RequestEditors, fn) + return nil + } +} + +func (p *WebhookInitiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range p.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 +} + +// WebhookInitiatorInterface is the interface specification for the webhook initiator. +type WebhookInitiatorInterface interface { + // EnterEventWithBody sends a POST webhook request + EnterEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + EnterEvent(ctx context.Context, targetURL string, body EnterEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // ExitEventWithBody sends a POST webhook request + ExitEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + ExitEvent(ctx context.Context, targetURL string, body ExitEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +// EnterEventWithBody sends a POST webhook request +// Person entered the building +func (p *WebhookInitiator) EnterEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewEnterEventWebhookRequestWithBody(targetURL, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// EnterEvent sends a POST webhook request with JSON body +func (p *WebhookInitiator) EnterEvent(ctx context.Context, targetURL string, body EnterEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewEnterEventWebhookRequest(targetURL, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// ExitEventWithBody sends a POST webhook request +// Person exited the building +func (p *WebhookInitiator) ExitEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewExitEventWebhookRequestWithBody(targetURL, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// ExitEvent sends a POST webhook request with JSON body +func (p *WebhookInitiator) ExitEvent(ctx context.Context, targetURL string, body ExitEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewExitEventWebhookRequest(targetURL, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} + +// NewEnterEventWebhookRequest creates a POST request for the webhook with application/json body +func NewEnterEventWebhookRequest(targetURL string, body EnterEventJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewEnterEventWebhookRequestWithBody(targetURL, "application/json", bodyReader) +} + +// NewEnterEventWebhookRequestWithBody creates a POST request for the webhook with any body +func NewEnterEventWebhookRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + parsedURL, err := url.Parse(targetURL) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", parsedURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewExitEventWebhookRequest creates a POST request for the webhook with application/json body +func NewExitEventWebhookRequest(targetURL string, body ExitEventJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewExitEventWebhookRequestWithBody(targetURL, "application/json", bodyReader) +} + +// NewExitEventWebhookRequestWithBody creates a POST request for the webhook with any body +func NewExitEventWebhookRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + parsedURL, err := url.Parse(targetURL) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", parsedURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// WebhookHttpError represents an HTTP error response. +// The type parameter E is the type of the parsed error body. +type WebhookHttpError[E any] struct { + StatusCode int + Body E + RawBody []byte +} + +func (e *WebhookHttpError[E]) Error() string { + return fmt.Sprintf("HTTP %d", e.StatusCode) +} + +// SimpleWebhookInitiator wraps WebhookInitiator with typed responses for operations that have +// unambiguous response types. Methods return the success type directly, +// and HTTP errors are returned as *WebhookHttpError[E] where E is the error type. +type SimpleWebhookInitiator struct { + *WebhookInitiator +} + +// NewSimpleWebhookInitiator creates a new SimpleWebhookInitiator which wraps a WebhookInitiator. +func NewSimpleWebhookInitiator(opts ...WebhookInitiatorOption) (*SimpleWebhookInitiator, error) { + initiator, err := NewWebhookInitiator(opts...) + if err != nil { + return nil, err + } + return &SimpleWebhookInitiator{WebhookInitiator: initiator}, nil +} + +// WebhookReceiverInterface represents handlers for receiving webhook requests. +type WebhookReceiverInterface interface { + // Person entered the building + // HandleEnterEventWebhook handles the POST webhook request. + HandleEnterEventWebhook(w http.ResponseWriter, r *http.Request) + // Person exited the building + // HandleExitEventWebhook handles the POST webhook request. + HandleExitEventWebhook(w http.ResponseWriter, r *http.Request) +} + +// WebhookReceiverMiddlewareFunc is a middleware function for webhook receiver handlers. +type WebhookReceiverMiddlewareFunc func(http.Handler) http.Handler + +// EnterEventWebhookHandler returns an http.Handler for the EnterEvent webhook. +// The caller is responsible for registering this handler at the appropriate path. +func EnterEventWebhookHandler(si WebhookReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...WebhookReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.HandleEnterEventWebhook(w, r) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} + +// ExitEventWebhookHandler returns an http.Handler for the ExitEvent webhook. +// The caller is responsible for registering this handler at the appropriate path. +func ExitEventWebhookHandler(si WebhookReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...WebhookReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.HandleExitEventWebhook(w, r) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} diff --git a/experimental/examples/webhook/server/main.go b/experimental/examples/webhook/server/main.go new file mode 100644 index 0000000000..8476aab7a8 --- /dev/null +++ b/experimental/examples/webhook/server/main.go @@ -0,0 +1,186 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "log" + "math/rand/v2" + "net" + "net/http" + "sync" + "time" + + "github.com/google/uuid" + + doorbadge "github.com/oapi-codegen/oapi-codegen/experimental/examples/webhook" +) + +var names = []string{ + "Alice", "Bob", "Charlie", "Diana", "Eve", + "Frank", "Grace", "Hank", "Iris", "Jack", +} + +type webhookEntry struct { + id uuid.UUID + url string + kind string +} + +// BadgeReader implements doorbadge.ServerInterface. +type BadgeReader struct { + initiator *doorbadge.WebhookInitiator + + mu sync.Mutex + webhooks map[uuid.UUID]webhookEntry +} + +var _ doorbadge.ServerInterface = (*BadgeReader)(nil) + +func NewBadgeReader() *BadgeReader { + initiator, err := doorbadge.NewWebhookInitiator() + if err != nil { + log.Fatalf("Failed to create webhook initiator: %v", err) + } + return &BadgeReader{ + initiator: initiator, + webhooks: make(map[uuid.UUID]webhookEntry), + } +} + +func sendError(w http.ResponseWriter, code int, message string) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(doorbadge.Error{ + Code: int32(code), + Message: message, + }) +} + +func (br *BadgeReader) RegisterWebhook(w http.ResponseWriter, r *http.Request, kind string) { + var req doorbadge.WebhookRegistration + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + sendError(w, http.StatusBadRequest, "Invalid request body: "+err.Error()) + return + } + + if kind != "enterEvent" && kind != "exitEvent" { + sendError(w, http.StatusBadRequest, "Invalid webhook kind: "+kind) + return + } + + id := uuid.New() + entry := webhookEntry{id: id, url: req.URL, kind: kind} + + br.mu.Lock() + br.webhooks[id] = entry + br.mu.Unlock() + + log.Printf("Registered webhook: id=%s kind=%s url=%s", id, kind, req.URL) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(doorbadge.WebhookRegistrationResponse{ID: id}) +} + +func (br *BadgeReader) DeregisterWebhook(w http.ResponseWriter, r *http.Request, id uuid.UUID) { + br.mu.Lock() + entry, ok := br.webhooks[id] + delete(br.webhooks, id) + br.mu.Unlock() + + if !ok { + sendError(w, http.StatusNotFound, "Webhook not found: "+id.String()) + return + } + + log.Printf("Deregistered webhook: id=%s kind=%s url=%s", id, entry.kind, entry.url) + w.WriteHeader(http.StatusNoContent) +} + +// generateEvents picks a random name and event kind every second and notifies webhooks. +func (br *BadgeReader) generateEvents(ctx context.Context) { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + name := names[rand.IntN(len(names))] + kind := "enterEvent" + if rand.IntN(2) == 0 { + kind = "exitEvent" + } + + person := doorbadge.Person{Name: name} + + br.mu.Lock() + targets := make([]webhookEntry, 0) + for _, entry := range br.webhooks { + if entry.kind == kind { + targets = append(targets, entry) + } + } + br.mu.Unlock() + + if len(targets) == 0 { + continue + } + + log.Printf("Event: %s %s (%d webhooks)", kind, name, len(targets)) + + for _, target := range targets { + var resp *http.Response + var err error + + switch kind { + case "enterEvent": + resp, err = br.initiator.EnterEvent(ctx, target.url, person) + case "exitEvent": + resp, err = br.initiator.ExitEvent(ctx, target.url, person) + } + + if err != nil { + log.Printf("Webhook %s failed: %v — removing", target.id, err) + br.mu.Lock() + delete(br.webhooks, target.id) + br.mu.Unlock() + continue + } + _ = resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + log.Printf("Webhook %s returned %d — removing", target.id, resp.StatusCode) + br.mu.Lock() + delete(br.webhooks, target.id) + br.mu.Unlock() + } + } + } + } +} + +func main() { + port := flag.String("port", "8080", "Port for HTTP server") + flag.Parse() + + reader := NewBadgeReader() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go reader.generateEvents(ctx) + + mux := http.NewServeMux() + doorbadge.HandlerFromMux(reader, mux) + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Printf("%s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) + mux.ServeHTTP(w, r) + }) + + addr := net.JoinHostPort("0.0.0.0", *port) + log.Printf("Door Badge Reader server listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, handler)) +} diff --git a/experimental/go.mod b/experimental/go.mod new file mode 100644 index 0000000000..70784976bf --- /dev/null +++ b/experimental/go.mod @@ -0,0 +1,27 @@ +module github.com/oapi-codegen/oapi-codegen/experimental + +go 1.24.0 + +require ( + github.com/google/uuid v1.6.0 + github.com/pb33f/libopenapi v0.33.5 + github.com/stretchr/testify v1.11.1 + go.yaml.in/yaml/v4 v4.0.0-rc.4 // required by libopenapi for Extensions type + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + golang.org/x/text v0.33.0 + golang.org/x/tools v0.41.0 +) + +require ( + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pb33f/jsonpath v0.7.1 // indirect + github.com/pb33f/ordered-map/v2 v2.3.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect +) diff --git a/experimental/go.sum b/experimental/go.sum new file mode 100644 index 0000000000..28075cb106 --- /dev/null +++ b/experimental/go.sum @@ -0,0 +1,41 @@ +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/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/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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/pb33f/jsonpath v0.7.1 h1:dEp6oIZuJbpDSyuHAl9m7GonoDW4M20BcD5vT0tPYRE= +github.com/pb33f/jsonpath v0.7.1/go.mod h1:zBV5LJW4OQOPatmQE2QdKpGQJvhDTlE5IEj6ASaRNTo= +github.com/pb33f/libopenapi v0.33.5 h1:AzILVrOzMaawLFhQENmwmn7h/TIDH2QEgUd0PfxS2xE= +github.com/pb33f/libopenapi v0.33.5/go.mod h1:e/dmd2Pf1nkjqkI0r7guFSyt9T5V0IIQKgs0L6B/3b0= +github.com/pb33f/ordered-map/v2 v2.3.0 h1:k2OhVEQkhTCQMhAicQ3Z6iInzoZNQ7L9MVomwKBZ5WQ= +github.com/pb33f/ordered-map/v2 v2.3.0/go.mod h1:oe5ue+6ZNhy7QN9cPZvPA23Hx0vMHnNVeMg4fGdCANw= +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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U= +go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/experimental/internal/codegen/clientgen.go b/experimental/internal/codegen/clientgen.go new file mode 100644 index 0000000000..759d9e2da1 --- /dev/null +++ b/experimental/internal/codegen/clientgen.go @@ -0,0 +1,349 @@ +package codegen + +import ( + "bytes" + "fmt" + "strings" + "text/template" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// ClientGenerator generates client code from operation descriptors. +type ClientGenerator struct { + tmpl *template.Template + schemaIndex map[string]*SchemaDescriptor + generateSimple bool + modelsPackage *ModelsPackage +} + +// NewClientGenerator creates a new client generator. +// modelsPackage can be nil if models are in the same package. +func NewClientGenerator(schemaIndex map[string]*SchemaDescriptor, generateSimple bool, modelsPackage *ModelsPackage) (*ClientGenerator, error) { + tmpl := template.New("client").Funcs(templates.Funcs()).Funcs(clientFuncs(schemaIndex, modelsPackage)) + + // Parse client templates + for _, ct := range templates.ClientTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + ct.Template) + if err != nil { + return nil, err + } + _, err = tmpl.New(ct.Name).Parse(string(content)) + if err != nil { + return nil, err + } + } + + // Parse shared templates (param_types is shared with server) + for _, st := range templates.SharedServerTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + st.Template) + if err != nil { + return nil, err + } + _, err = tmpl.New(st.Name).Parse(string(content)) + if err != nil { + return nil, err + } + } + + return &ClientGenerator{ + tmpl: tmpl, + schemaIndex: schemaIndex, + generateSimple: generateSimple, + modelsPackage: modelsPackage, + }, nil +} + +// clientFuncs returns template functions specific to client generation. +func clientFuncs(schemaIndex map[string]*SchemaDescriptor, modelsPackage *ModelsPackage) template.FuncMap { + return template.FuncMap{ + "pathFmt": pathFmt, + "isSimpleOperation": isSimpleOperation, + "simpleOperationSuccessResponse": simpleOperationSuccessResponse, + "errorResponseForOperation": errorResponseForOperation, + "goTypeForContent": func(content *ResponseContentDescriptor) string { + return goTypeForContent(content, schemaIndex, modelsPackage) + }, + "modelsPkg": func() string { + return modelsPackage.Prefix() + }, + } +} + +// pathFmt converts a path with {param} placeholders to a format string. +// Example: "/pets/{petId}" -> "/pets/%s" +func pathFmt(path string) string { + result := path + for { + start := strings.Index(result, "{") + if start == -1 { + break + } + end := strings.Index(result, "}") + if end == -1 { + break + } + result = result[:start] + "%s" + result[end+1:] + } + return result +} + +// isSimpleOperation returns true if an operation has a single JSON success response type. +// "Simple" operations can have typed wrapper methods in SimpleClient. +func isSimpleOperation(op *OperationDescriptor) bool { + // Must have responses + if len(op.Responses) == 0 { + return false + } + + // Count success responses (2xx or default that could be success) + var successResponses []*ResponseDescriptor + for _, r := range op.Responses { + if strings.HasPrefix(r.StatusCode, "2") { + successResponses = append(successResponses, r) + } + } + + // Must have exactly one success response + if len(successResponses) != 1 { + return false + } + + success := successResponses[0] + + // Must have at least one content type and exactly one JSON content type + // (i.e., if there are multiple content types, we can't have a simple typed response) + if len(success.Contents) == 0 { + return false + } + if len(success.Contents) != 1 { + return false + } + + // The single content type must be JSON + return success.Contents[0].IsJSON +} + +// simpleOperationSuccessResponse returns the single success response for a simple operation. +func simpleOperationSuccessResponse(op *OperationDescriptor) *ResponseDescriptor { + for _, r := range op.Responses { + if strings.HasPrefix(r.StatusCode, "2") { + return r + } + } + return nil +} + +// errorResponseForOperation returns the error response (default or 4xx/5xx) if one exists. +func errorResponseForOperation(op *OperationDescriptor) *ResponseDescriptor { + // First, look for a default response + for _, r := range op.Responses { + if r.StatusCode == "default" { + if len(r.Contents) > 0 && r.Contents[0].IsJSON { + return r + } + } + } + // Then look for a 4xx or 5xx response + for _, r := range op.Responses { + if strings.HasPrefix(r.StatusCode, "4") || strings.HasPrefix(r.StatusCode, "5") { + if len(r.Contents) > 0 && r.Contents[0].IsJSON { + return r + } + } + } + return nil +} + +// goTypeForContent returns the Go type for a response content descriptor. +// If modelsPackage is set, type names are prefixed with the package name. +func goTypeForContent(content *ResponseContentDescriptor, schemaIndex map[string]*SchemaDescriptor, modelsPackage *ModelsPackage) string { + if content == nil || content.Schema == nil { + return "interface{}" + } + + pkgPrefix := modelsPackage.Prefix() + + // If the schema has a reference, look it up + if content.Schema.Ref != "" { + if target, ok := schemaIndex[content.Schema.Ref]; ok { + return pkgPrefix + target.ShortName + } + } + + // Check if this is an array schema with items that have a reference + if content.Schema.Schema != nil && content.Schema.Schema.Items != nil { + itemProxy := content.Schema.Schema.Items.A + if itemProxy != nil && itemProxy.IsReference() { + ref := itemProxy.GetReference() + if target, ok := schemaIndex[ref]; ok { + return "[]" + pkgPrefix + target.ShortName + } + } + } + + // If the schema has a short name, use it + if content.Schema.ShortName != "" { + return pkgPrefix + content.Schema.ShortName + } + + // Fall back to the stable name + if content.Schema.StableName != "" { + return pkgPrefix + content.Schema.StableName + } + + // Try to derive from the schema itself + if content.Schema.Schema != nil { + return schemaToGoType(content.Schema.Schema) + } + + return "interface{}" +} + +// GenerateBase generates the base client types and helpers. +func (g *ClientGenerator) GenerateBase() (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "base", nil); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateInterface generates the ClientInterface. +func (g *ClientGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "interface", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateMethods generates the Client methods. +func (g *ClientGenerator) GenerateMethods(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "methods", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateRequestBuilders generates the request builder functions. +func (g *ClientGenerator) GenerateRequestBuilders(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "request_builders", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateSimple generates the SimpleClient with typed responses. +func (g *ClientGenerator) GenerateSimple(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "simple", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateParamTypes generates the parameter struct types. +func (g *ClientGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateRequestBodyTypes generates type aliases for request bodies. +func (g *ClientGenerator) GenerateRequestBodyTypes(ops []*OperationDescriptor) string { + var buf bytes.Buffer + pkgPrefix := g.modelsPackage.Prefix() + + for _, op := range ops { + for _, body := range op.Bodies { + if !body.IsJSON { + continue + } + // Get the underlying type for this request body + var targetType string + if body.Schema != nil { + if body.Schema.Ref != "" { + // Reference to a component schema + if target, ok := g.schemaIndex[body.Schema.Ref]; ok { + targetType = pkgPrefix + target.ShortName + } + } else if body.Schema.ShortName != "" { + targetType = pkgPrefix + body.Schema.ShortName + } + } + if targetType == "" { + targetType = "interface{}" + } + + // Generate type alias: type addPetJSONRequestBody = models.NewPet + buf.WriteString(fmt.Sprintf("type %s = %s\n\n", body.GoTypeName, targetType)) + } + } + + return buf.String() +} + +// GenerateClient generates the complete client code. +func (g *ClientGenerator) GenerateClient(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + + // Generate request body type aliases first + bodyTypes := g.GenerateRequestBodyTypes(ops) + buf.WriteString(bodyTypes) + + // Generate base client + base, err := g.GenerateBase() + if err != nil { + return "", fmt.Errorf("generating base client: %w", err) + } + buf.WriteString(base) + buf.WriteString("\n") + + // Generate interface + iface, err := g.GenerateInterface(ops) + if err != nil { + return "", fmt.Errorf("generating client interface: %w", err) + } + buf.WriteString(iface) + buf.WriteString("\n") + + // Generate param types + paramTypes, err := g.GenerateParamTypes(ops) + if err != nil { + return "", fmt.Errorf("generating param types: %w", err) + } + buf.WriteString(paramTypes) + buf.WriteString("\n") + + // Generate methods + methods, err := g.GenerateMethods(ops) + if err != nil { + return "", fmt.Errorf("generating client methods: %w", err) + } + buf.WriteString(methods) + buf.WriteString("\n") + + // Generate request builders + builders, err := g.GenerateRequestBuilders(ops) + if err != nil { + return "", fmt.Errorf("generating request builders: %w", err) + } + buf.WriteString(builders) + buf.WriteString("\n") + + // Generate simple client if requested + if g.generateSimple { + simple, err := g.GenerateSimple(ops) + if err != nil { + return "", fmt.Errorf("generating simple client: %w", err) + } + buf.WriteString(simple) + } + + return buf.String(), nil +} diff --git a/experimental/internal/codegen/clientgen_test.go b/experimental/internal/codegen/clientgen_test.go new file mode 100644 index 0000000000..cb5d6961b5 --- /dev/null +++ b/experimental/internal/codegen/clientgen_test.go @@ -0,0 +1,188 @@ +package codegen + +import ( + "os" + "testing" + + "github.com/pb33f/libopenapi" + "github.com/stretchr/testify/require" +) + +func TestClientGenerator(t *testing.T) { + // Read the petstore spec + specPath := "../../examples/petstore-expanded/petstore-expanded.yaml" + specData, err := os.ReadFile(specPath) + require.NoError(t, err, "Failed to read petstore spec") + + // Parse the spec + doc, err := libopenapi.NewDocument(specData) + require.NoError(t, err, "Failed to parse petstore spec") + + // Gather schemas to build schema index + contentTypeMatcher := NewContentTypeMatcher(DefaultContentTypes()) + schemas, err := GatherSchemas(doc, contentTypeMatcher) + require.NoError(t, err, "Failed to gather schemas") + + // Compute names for schemas + converter := NewNameConverter(NameMangling{}, NameSubstitutions{}) + contentTypeNamer := NewContentTypeShortNamer(DefaultContentTypeShortNames()) + ComputeSchemaNames(schemas, converter, contentTypeNamer) + + // Build schema index - key by Path.String() for component schemas + schemaIndex := make(map[string]*SchemaDescriptor) + for _, s := range schemas { + schemaIndex[s.Path.String()] = s + } + + // Create param tracker + paramTracker := NewParamUsageTracker() + + // Gather operations + ops, err := GatherOperations(doc, paramTracker) + require.NoError(t, err, "Failed to gather operations") + require.Len(t, ops, 4, "Expected 4 operations") + + // Log operations for debugging + // Verify we have the expected operations + operationIDs := make([]string, 0, len(ops)) + for _, op := range ops { + operationIDs = append(operationIDs, op.GoOperationID) + } + t.Logf("Operations: %v", operationIDs) + + // Generate client code + gen, err := NewClientGenerator(schemaIndex, true, nil) + require.NoError(t, err, "Failed to create client generator") + + clientCode, err := gen.GenerateClient(ops) + require.NoError(t, err, "Failed to generate client code") + require.NotEmpty(t, clientCode, "Generated client code should not be empty") + + t.Logf("Generated client code:\n%s", clientCode) + + // Verify key components are present + require.Contains(t, clientCode, "type Client struct") + require.Contains(t, clientCode, "NewClient") + require.Contains(t, clientCode, "type ClientInterface interface") + require.Contains(t, clientCode, "FindPets") + require.Contains(t, clientCode, "AddPet") + require.Contains(t, clientCode, "DeletePet") + require.Contains(t, clientCode, "FindPetByID") + + // Verify request builders + require.Contains(t, clientCode, "NewFindPetsRequest") + require.Contains(t, clientCode, "NewAddPetRequest") + require.Contains(t, clientCode, "NewDeletePetRequest") + require.Contains(t, clientCode, "NewFindPetByIDRequest") + + // Verify SimpleClient + require.Contains(t, clientCode, "type SimpleClient struct") + require.Contains(t, clientCode, "NewSimpleClient") +} + +func TestIsSimpleOperation(t *testing.T) { + tests := []struct { + name string + op *OperationDescriptor + expected bool + }{ + { + name: "simple operation with single JSON 200 response", + op: &OperationDescriptor{ + Responses: []*ResponseDescriptor{ + { + StatusCode: "200", + Contents: []*ResponseContentDescriptor{ + {ContentType: "application/json", IsJSON: true}, + }, + }, + }, + }, + expected: true, + }, + { + name: "not simple - multiple success responses", + op: &OperationDescriptor{ + Responses: []*ResponseDescriptor{ + { + StatusCode: "200", + Contents: []*ResponseContentDescriptor{ + {ContentType: "application/json", IsJSON: true}, + }, + }, + { + StatusCode: "201", + Contents: []*ResponseContentDescriptor{ + {ContentType: "application/json", IsJSON: true}, + }, + }, + }, + }, + expected: false, + }, + { + name: "not simple - multiple content types", + op: &OperationDescriptor{ + Responses: []*ResponseDescriptor{ + { + StatusCode: "200", + Contents: []*ResponseContentDescriptor{ + {ContentType: "application/json", IsJSON: true}, + {ContentType: "application/xml", IsJSON: false}, + }, + }, + }, + }, + expected: false, + }, + { + name: "not simple - no JSON content", + op: &OperationDescriptor{ + Responses: []*ResponseDescriptor{ + { + StatusCode: "200", + Contents: []*ResponseContentDescriptor{ + {ContentType: "text/plain", IsJSON: false}, + }, + }, + }, + }, + expected: false, + }, + { + name: "not simple - no responses", + op: &OperationDescriptor{}, + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := isSimpleOperation(tc.op) + if result != tc.expected { + t.Errorf("isSimpleOperation() = %v, expected %v", result, tc.expected) + } + }) + } +} + +func TestPathFmt(t *testing.T) { + tests := []struct { + path string + expected string + }{ + {"/pets", "/pets"}, + {"/pets/{petId}", "/pets/%s"}, + {"/pets/{petId}/photos/{photoId}", "/pets/%s/photos/%s"}, + {"/users/{userId}/posts/{postId}/comments/{commentId}", "/users/%s/posts/%s/comments/%s"}, + } + + for _, tc := range tests { + t.Run(tc.path, func(t *testing.T) { + result := pathFmt(tc.path) + if result != tc.expected { + t.Errorf("pathFmt(%q) = %q, expected %q", tc.path, result, tc.expected) + } + }) + } +} diff --git a/experimental/internal/codegen/codegen.go b/experimental/internal/codegen/codegen.go new file mode 100644 index 0000000000..5b6fdff894 --- /dev/null +++ b/experimental/internal/codegen/codegen.go @@ -0,0 +1,1101 @@ +// Package codegen generates Go code from parsed OpenAPI specs. +package codegen + +import ( + "fmt" + "maps" + "slices" + "strings" + "text/template" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel/high/base" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// Generate produces Go code from the parsed OpenAPI document. +// specData is the raw spec bytes used to embed the spec in the generated code. +func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (string, error) { + cfg.ApplyDefaults() + + // Create content type matcher for filtering request/response bodies + contentTypeMatcher := NewContentTypeMatcher(cfg.ContentTypes) + + // Create content type short namer for friendly type names + contentTypeNamer := NewContentTypeShortNamer(cfg.ContentTypeShortNames) + + // Pass 1: Gather all schemas that need types + schemas, err := GatherSchemas(doc, contentTypeMatcher) + if err != nil { + return "", fmt.Errorf("gathering schemas: %w", err) + } + + // Pass 2: Compute names for all schemas + converter := NewNameConverter(cfg.NameMangling, cfg.NameSubstitutions) + ComputeSchemaNames(schemas, converter, contentTypeNamer) + + // Build schema index for type resolution + schemaIndex := make(map[string]*SchemaDescriptor) + for _, s := range schemas { + schemaIndex[s.Path.String()] = s + } + + // Pass 3: Generate Go code + importResolver := NewImportResolver(cfg.ImportMapping) + tagGenerator := NewStructTagGenerator(cfg.StructTags) + gen := NewTypeGenerator(cfg.TypeMapping, converter, importResolver, tagGenerator) + gen.IndexSchemas(schemas) + + output := NewOutput(cfg.PackageName) + // Note: encoding/json and fmt imports are added by generateType when needed + + // Generate models (types for schemas) unless using external models package + if cfg.Generation.ModelsPackage == nil { + for _, desc := range schemas { + code := generateType(gen, desc) + if code != "" { + output.AddType(code) + } + } + + // Add imports collected during generation + output.AddImports(gen.Imports()) + + // Add custom type templates (Date, Email, UUID, File, etc.) + // Sort template names for deterministic output ordering. + templateNames := slices.Sorted(maps.Keys(gen.RequiredTemplates())) + for _, templateName := range templateNames { + typeCode, typeImports := loadCustomType(templateName) + if typeCode != "" { + output.AddType(typeCode) + for path, alias := range typeImports { + output.AddImport(path, alias) + } + } + } + + // Embed the raw OpenAPI spec if specData was provided + if len(specData) > 0 { + embeddedCode, err := generateEmbeddedSpec(specData) + if err != nil { + return "", fmt.Errorf("generating embedded spec: %w", err) + } + output.AddType(embeddedCode) + output.AddImport("bytes", "") + output.AddImport("compress/gzip", "") + output.AddImport("encoding/base64", "") + output.AddImport("fmt", "") + output.AddImport("strings", "") + output.AddImport("sync", "") + } + } + + // Generate client code if requested + if cfg.Generation.Client { + // Create param tracker for tracking which param functions are needed + paramTracker := NewParamUsageTracker() + + // Gather operations + ops, err := GatherOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering operations: %w", err) + } + + // Generate client + clientGen, err := NewClientGenerator(schemaIndex, cfg.Generation.SimpleClient, cfg.Generation.ModelsPackage) + if err != nil { + return "", fmt.Errorf("creating client generator: %w", err) + } + + clientCode, err := clientGen.GenerateClient(ops) + if err != nil { + return "", fmt.Errorf("generating client code: %w", err) + } + output.AddType(clientCode) + + // Add client imports + for _, ct := range templates.ClientTemplates { + for _, imp := range ct.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + // Add models package import if using external models + if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { + output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) + } + + // Generate param functions + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + + // Add param function imports + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + + // Track whether shared error types have been generated to avoid duplication. + // Both server and receiver generation emit the same error types. + generatedErrors := false + + // Generate server code for path operations if a server framework is set. + // Only generate if there are actual path operations — setting server solely + // for receiver use should not produce path-operation server code. + if cfg.Generation.Server != "" { + // Create param tracker for tracking which param functions are needed + paramTracker := NewParamUsageTracker() + + // Gather operations + ops, err := GatherOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering operations: %w", err) + } + + if len(ops) > 0 { + // Generate server + serverGen, err := NewServerGenerator(cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("creating server generator: %w", err) + } + + serverCode, err := serverGen.GenerateServer(ops) + if err != nil { + return "", fmt.Errorf("generating server code: %w", err) + } + output.AddType(serverCode) + generatedErrors = true + + // Add server imports based on server type + serverTemplates, err := getServerTemplates(cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("getting server templates: %w", err) + } + for _, st := range serverTemplates { + for _, imp := range st.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + // Note: Server interfaces don't use external models directly. + // Models are used in the hand-written implementation (petstore.go), + // not in the generated server interface code. + + // Generate param functions + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + + // Add param function imports + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + } + + // Generate webhook initiator code if requested + if cfg.Generation.WebhookInitiator { + paramTracker := NewParamUsageTracker() + + webhookOps, err := GatherWebhookOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering webhook operations: %w", err) + } + + if len(webhookOps) > 0 { + initiatorGen, err := NewInitiatorGenerator("Webhook", schemaIndex, true, cfg.Generation.ModelsPackage) + if err != nil { + return "", fmt.Errorf("creating webhook initiator generator: %w", err) + } + + initiatorCode, err := initiatorGen.GenerateInitiator(webhookOps) + if err != nil { + return "", fmt.Errorf("generating webhook initiator code: %w", err) + } + output.AddType(initiatorCode) + + for _, pt := range templates.InitiatorTemplates { + for _, imp := range pt.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { + output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) + } + + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + } + + // Generate callback initiator code if requested + if cfg.Generation.CallbackInitiator { + paramTracker := NewParamUsageTracker() + + callbackOps, err := GatherCallbackOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering callback operations: %w", err) + } + + if len(callbackOps) > 0 { + initiatorGen, err := NewInitiatorGenerator("Callback", schemaIndex, true, cfg.Generation.ModelsPackage) + if err != nil { + return "", fmt.Errorf("creating callback initiator generator: %w", err) + } + + initiatorCode, err := initiatorGen.GenerateInitiator(callbackOps) + if err != nil { + return "", fmt.Errorf("generating callback initiator code: %w", err) + } + output.AddType(initiatorCode) + + for _, pt := range templates.InitiatorTemplates { + for _, imp := range pt.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { + output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) + } + + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + } + + // Generate webhook receiver code if requested + if cfg.Generation.WebhookReceiver { + if cfg.Generation.Server == "" { + return "", fmt.Errorf("webhook-receiver requires server to be set") + } + + paramTracker := NewParamUsageTracker() + + webhookOps, err := GatherWebhookOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering webhook operations: %w", err) + } + + if len(webhookOps) > 0 { + receiverGen, err := NewReceiverGenerator("Webhook", cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("creating webhook receiver generator: %w", err) + } + + receiverCode, err := receiverGen.GenerateReceiver(webhookOps) + if err != nil { + return "", fmt.Errorf("generating webhook receiver code: %w", err) + } + output.AddType(receiverCode) + + // Add param types + paramTypes, err := receiverGen.GenerateParamTypes(webhookOps) + if err != nil { + return "", fmt.Errorf("generating webhook receiver param types: %w", err) + } + output.AddType(paramTypes) + + // Add error types (only if not already generated by server) + if !generatedErrors { + errors, err := receiverGen.GenerateErrors() + if err != nil { + return "", fmt.Errorf("generating webhook receiver errors: %w", err) + } + output.AddType(errors) + generatedErrors = true + } + + receiverTemplates, err := getReceiverTemplates(cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("getting receiver templates: %w", err) + } + for _, ct := range receiverTemplates { + for _, imp := range ct.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + for _, st := range templates.SharedServerTemplates { + for _, imp := range st.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + } + + // Generate callback receiver code if requested + if cfg.Generation.CallbackReceiver { + if cfg.Generation.Server == "" { + return "", fmt.Errorf("callback-receiver requires server to be set") + } + + paramTracker := NewParamUsageTracker() + + callbackOps, err := GatherCallbackOperations(doc, paramTracker) + if err != nil { + return "", fmt.Errorf("gathering callback operations: %w", err) + } + + if len(callbackOps) > 0 { + receiverGen, err := NewReceiverGenerator("Callback", cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("creating callback receiver generator: %w", err) + } + + receiverCode, err := receiverGen.GenerateReceiver(callbackOps) + if err != nil { + return "", fmt.Errorf("generating callback receiver code: %w", err) + } + output.AddType(receiverCode) + + paramTypes, err := receiverGen.GenerateParamTypes(callbackOps) + if err != nil { + return "", fmt.Errorf("generating callback receiver param types: %w", err) + } + output.AddType(paramTypes) + + // Add error types (only if not already generated by server or another receiver) + if !generatedErrors { + errors, err := receiverGen.GenerateErrors() + if err != nil { + return "", fmt.Errorf("generating callback receiver errors: %w", err) + } + output.AddType(errors) + generatedErrors = true //nolint:ineffassign // kept for symmetry with webhook loop below + } + + receiverTemplates, err := getReceiverTemplates(cfg.Generation.Server) + if err != nil { + return "", fmt.Errorf("getting receiver templates: %w", err) + } + for _, ct := range receiverTemplates { + for _, imp := range ct.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + for _, st := range templates.SharedServerTemplates { + for _, imp := range st.Imports { + output.AddImport(imp.Path, imp.Alias) + } + } + + paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) + if err != nil { + return "", fmt.Errorf("generating param functions: %w", err) + } + if paramFuncs != "" { + output.AddType(paramFuncs) + } + for _, imp := range paramTracker.GetRequiredImports() { + output.AddImport(imp.Path, imp.Alias) + } + } + } + + return output.Format() +} + +// generateParamFunctionsFromTracker generates the parameter styling/binding functions based on usage. +func generateParamFunctionsFromTracker(tracker *ParamUsageTracker) (string, error) { + if !tracker.HasAnyUsage() { + return "", nil + } + + var result strings.Builder + + // Get required templates + requiredTemplates := tracker.GetRequiredTemplates() + + for _, tmplInfo := range requiredTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + tmplInfo.Template) + if err != nil { + return "", fmt.Errorf("reading param template %s: %w", tmplInfo.Template, err) + } + + // Parse and execute as a Go template + tmpl, err := template.New(tmplInfo.Name).Parse(string(content)) + if err != nil { + return "", fmt.Errorf("parsing param template %s: %w", tmplInfo.Template, err) + } + + if err := tmpl.Execute(&result, nil); err != nil { + return "", fmt.Errorf("executing param template %s: %w", tmplInfo.Template, err) + } + result.WriteString("\n") + } + + return result.String(), nil +} + +// generateType generates Go code for a single schema descriptor. +func generateType(gen *TypeGenerator, desc *SchemaDescriptor) string { + kind := GetSchemaKind(desc) + + // If schema has TypeOverride extension, generate a type alias to the external type + // instead of generating the full type definition + if desc.Extensions != nil && desc.Extensions.TypeOverride != nil { + return generateTypeOverrideAlias(gen, desc) + } + + var code string + switch kind { + case KindReference: + // References don't generate new types; they use the referenced type's name + return "" + + case KindStruct: + code = generateStructType(gen, desc) + + case KindMap: + code = generateMapAlias(gen, desc) + + case KindEnum: + code = generateEnumType(gen, desc) + + case KindAllOf: + code = generateAllOfType(gen, desc) + + case KindAnyOf: + code = generateAnyOfType(gen, desc) + + case KindOneOf: + code = generateOneOfType(gen, desc) + + case KindAlias: + code = generateTypeAlias(gen, desc) + + default: + return "" + } + + if code == "" { + return "" + } + + // Prepend schema path comment + return schemaPathComment(desc.Path) + code +} + +// schemaPathComment returns a comment line showing the schema path. +func schemaPathComment(path SchemaPath) string { + return fmt.Sprintf("// %s\n", path.String()) +} + +// generateStructType generates a struct type for an object schema. +func generateStructType(gen *TypeGenerator, desc *SchemaDescriptor) string { + fields := gen.GenerateStructFields(desc) + doc := extractDescription(desc.Schema) + + // Check if we need additionalProperties handling + if gen.HasAdditionalProperties(desc) { + // Mixed properties need encoding/json for marshal/unmarshal (but not fmt) + gen.AddJSONImport() + + addPropsType := gen.AdditionalPropertiesType(desc) + structCode := GenerateStructWithAdditionalProps(desc.ShortName, fields, addPropsType, doc, gen.TagGenerator()) + + // Generate marshal/unmarshal methods + marshalCode := GenerateMixedPropertiesMarshal(desc.ShortName, fields) + unmarshalCode := GenerateMixedPropertiesUnmarshal(desc.ShortName, fields, addPropsType) + + code := structCode + "\n" + marshalCode + "\n" + unmarshalCode + + // Generate ApplyDefaults method if needed + if applyDefaults := GenerateApplyDefaults(desc.ShortName, fields); applyDefaults != "" { + code += "\n" + applyDefaults + } + + return code + } + + code := GenerateStruct(desc.ShortName, fields, doc, gen.TagGenerator()) + + // Generate ApplyDefaults method if needed + if applyDefaults := GenerateApplyDefaults(desc.ShortName, fields); applyDefaults != "" { + code += "\n" + applyDefaults + } + + return code +} + +// generateMapAlias generates a type alias for a pure map schema. +func generateMapAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { + mapType := gen.GoTypeExpr(desc) + doc := extractDescription(desc.Schema) + return GenerateTypeAlias(desc.ShortName, mapType, doc) +} + +// generateEnumType generates an enum type with const values. +func generateEnumType(gen *TypeGenerator, desc *SchemaDescriptor) string { + schema := desc.Schema + if schema == nil { + return "" + } + + // Determine base type + baseType := "string" + primaryType := getPrimaryType(schema) + if primaryType == "integer" { + baseType = "int" + } + + // Extract enum values as strings + var values []string + for _, v := range schema.Enum { + values = append(values, fmt.Sprintf("%v", v.Value)) + } + + // Check for custom enum variable names from extensions + var customNames []string + if desc.Extensions != nil && len(desc.Extensions.EnumVarNames) > 0 { + customNames = desc.Extensions.EnumVarNames + } + + doc := extractDescription(schema) + return GenerateEnumWithConstPrefix(desc.ShortName, desc.ShortName, baseType, values, customNames, doc) +} + +// generateTypeAlias generates a simple type alias. +func generateTypeAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { + goType := gen.GoTypeExpr(desc) + doc := extractDescription(desc.Schema) + return GenerateTypeAlias(desc.ShortName, goType, doc) +} + +// generateTypeOverrideAlias generates a type alias to an external type specified via x-oapi-codegen-type-override. +func generateTypeOverrideAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { + override := desc.Extensions.TypeOverride + + // Register the import + if override.ImportPath != "" { + if override.ImportAlias != "" { + gen.AddImportAlias(override.ImportPath, override.ImportAlias) + } else { + gen.AddImport(override.ImportPath) + } + } + + doc := extractDescription(desc.Schema) + return GenerateTypeAlias(desc.ShortName, override.TypeName, doc) +} + +// AllOfMergeError represents a conflict when merging allOf schemas. +type AllOfMergeError struct { + SchemaName string + PropertyName string + Type1 string + Type2 string +} + +func (e AllOfMergeError) Error() string { + return fmt.Sprintf("allOf merge conflict in %s: property %q has conflicting types %s and %s", + e.SchemaName, e.PropertyName, e.Type1, e.Type2) +} + +// allOfMemberInfo holds information about an allOf member for merging. +type allOfMemberInfo struct { + fields []StructField // flattened fields from object schemas + unionType string // non-empty if this member is a oneOf/anyOf union + unionDesc *SchemaDescriptor + required []string // required fields from this allOf member +} + +// generateAllOfType generates a struct with flattened properties from all allOf members. +// Object schema properties are merged into flat fields. +// oneOf/anyOf members become union fields with json:"-" tag. +func generateAllOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { + schema := desc.Schema + if schema == nil { + return "" + } + + // Merge all fields, checking for conflicts + mergedFields := make(map[string]StructField) // keyed by JSONName + var fieldOrder []string // preserve order + var unionFields []StructField + + // First, collect fields from properties defined directly on the schema + // (Issue 2102: properties at same level as allOf were being ignored) + if schema.Properties != nil && schema.Properties.Len() > 0 { + directFields := gen.GenerateStructFields(desc) + for _, field := range directFields { + mergedFields[field.JSONName] = field + fieldOrder = append(fieldOrder, field.JSONName) + } + } + + // Collect info about each allOf member + var members []allOfMemberInfo + for i, proxy := range schema.AllOf { + info := allOfMemberInfo{} + + memberSchema := proxy.Schema() + if memberSchema == nil { + continue + } + + // Check if this member is a oneOf/anyOf (union type) + if len(memberSchema.OneOf) > 0 || len(memberSchema.AnyOf) > 0 { + // This is a union - keep as a union field + if desc.AllOf != nil && i < len(desc.AllOf) { + info.unionType = desc.AllOf[i].ShortName + info.unionDesc = desc.AllOf[i] + } + } else if proxy.IsReference() { + // Reference to another schema - get its fields + ref := proxy.GetReference() + if target, ok := gen.schemaIndex[ref]; ok { + info.fields = gen.collectFieldsRecursive(target) + } + } else if memberSchema.Properties != nil && memberSchema.Properties.Len() > 0 { + // Inline object schema - get its fields + if desc.AllOf != nil && i < len(desc.AllOf) { + info.fields = gen.GenerateStructFields(desc.AllOf[i]) + } + } + + // Also check for required array in allOf members (may mark fields as required) + info.required = memberSchema.Required + + members = append(members, info) + } + + // Merge fields from allOf members + for _, member := range members { + if member.unionType != "" { + // Add union as a special field + unionFields = append(unionFields, StructField{ + Name: member.unionType, + Type: "*" + member.unionType, + JSONName: "-", // will use json:"-" + }) + continue + } + + for _, field := range member.fields { + if existing, ok := mergedFields[field.JSONName]; ok { + // Check for type conflict + if existing.Type != field.Type { + // Type conflict - generate error comment in output + // In a real implementation, this should be a proper error + // For now, we'll include a comment and use the first type + field.Doc = fmt.Sprintf("CONFLICT: type %s vs %s", existing.Type, field.Type) + } + // If same type, keep existing (first wins for required/nullable) + continue + } + mergedFields[field.JSONName] = field + fieldOrder = append(fieldOrder, field.JSONName) + } + + // Apply required array from this allOf member to update pointer/omitempty + for _, reqName := range member.required { + if field, ok := mergedFields[reqName]; ok { + if !field.Required { + field.Required = true + field.OmitEmpty = false + // Update pointer status - required non-nullable fields are not pointers + if !field.Nullable && !strings.HasPrefix(field.Type, "[]") && !strings.HasPrefix(field.Type, "map[") { + field.Type = strings.TrimPrefix(field.Type, "*") + field.Pointer = false + } + mergedFields[reqName] = field + } + } + } + } + + // Build final field list in order + var finalFields []StructField + for _, jsonName := range fieldOrder { + finalFields = append(finalFields, mergedFields[jsonName]) + } + + doc := extractDescription(schema) + + // Generate struct + var code string + if len(unionFields) > 0 { + // Has union members - need custom marshal/unmarshal + gen.AddJSONImport() + code = generateAllOfStructWithUnions(desc.ShortName, finalFields, unionFields, doc, gen.TagGenerator()) + } else { + // Simple case - just flattened fields + code = GenerateStruct(desc.ShortName, finalFields, doc, gen.TagGenerator()) + } + + // Generate ApplyDefaults method if needed + if applyDefaults := GenerateApplyDefaults(desc.ShortName, finalFields); applyDefaults != "" { + code += "\n" + applyDefaults + } + + return code +} + +// generateAllOfStructWithUnions generates an allOf struct that contains union fields. +func generateAllOfStructWithUnions(name string, fields []StructField, unionFields []StructField, doc string, tagGen *StructTagGenerator) string { + b := NewCodeBuilder() + + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + b.Line("type %s struct {", name) + b.Indent() + + // Regular fields + for _, f := range fields { + tag := generateFieldTag(f, tagGen) + b.Line("%s %s %s", f.Name, f.Type, tag) + } + + // Union fields with json:"-" + for _, f := range unionFields { + b.Line("%s %s `json:\"-\"`", f.Name, f.Type) + } + + b.Dedent() + b.Line("}") + + // Generate MarshalJSON + b.BlankLine() + b.Line("func (s %s) MarshalJSON() ([]byte, error) {", name) + b.Indent() + b.Line("result := make(map[string]any)") + b.BlankLine() + + // Marshal regular fields + for _, f := range fields { + if f.Pointer { + b.Line("if s.%s != nil {", f.Name) + b.Indent() + b.Line("result[%q] = s.%s", f.JSONName, f.Name) + b.Dedent() + b.Line("}") + } else if strings.HasPrefix(f.Type, "[]") || strings.HasPrefix(f.Type, "map[") { + // Slices and maps - only include if not nil + b.Line("if s.%s != nil {", f.Name) + b.Indent() + b.Line("result[%q] = s.%s", f.JSONName, f.Name) + b.Dedent() + b.Line("}") + } else { + b.Line("result[%q] = s.%s", f.JSONName, f.Name) + } + } + + // Marshal and merge union fields + for _, f := range unionFields { + b.BlankLine() + b.Line("if s.%s != nil {", f.Name) + b.Indent() + b.Line("unionData, err := json.Marshal(s.%s)", f.Name) + b.Line("if err != nil {") + b.Indent() + b.Line("return nil, err") + b.Dedent() + b.Line("}") + b.Line("var unionMap map[string]any") + b.Line("if err := json.Unmarshal(unionData, &unionMap); err == nil {") + b.Indent() + b.Line("for k, v := range unionMap {") + b.Indent() + b.Line("result[k] = v") + b.Dedent() + b.Line("}") + b.Dedent() + b.Line("}") + b.Dedent() + b.Line("}") + } + + b.BlankLine() + b.Line("return json.Marshal(result)") + b.Dedent() + b.Line("}") + + // Generate UnmarshalJSON + b.BlankLine() + b.Line("func (s *%s) UnmarshalJSON(data []byte) error {", name) + b.Indent() + + // Unmarshal into raw map for field extraction + b.Line("var raw map[string]json.RawMessage") + b.Line("if err := json.Unmarshal(data, &raw); err != nil {") + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.BlankLine() + + // Unmarshal known fields + for _, f := range fields { + b.Line("if v, ok := raw[%q]; ok {", f.JSONName) + b.Indent() + if f.Pointer { + baseType := strings.TrimPrefix(f.Type, "*") + b.Line("var val %s", baseType) + b.Line("if err := json.Unmarshal(v, &val); err != nil {") + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.Line("s.%s = &val", f.Name) + } else { + b.Line("if err := json.Unmarshal(v, &s.%s); err != nil {", f.Name) + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + } + b.Dedent() + b.Line("}") + } + + // Unmarshal union fields from the full data + for _, f := range unionFields { + b.BlankLine() + baseType := strings.TrimPrefix(f.Type, "*") + b.Line("var %sVal %s", f.Name, baseType) + b.Line("if err := json.Unmarshal(data, &%sVal); err != nil {", f.Name) + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.Line("s.%s = &%sVal", f.Name, f.Name) + } + + b.BlankLine() + b.Line("return nil") + b.Dedent() + b.Line("}") + + return b.String() +} + +// generateAnyOfType generates a union type for anyOf schemas. +func generateAnyOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { + members := collectUnionMembers(gen, desc, desc.AnyOf, desc.Schema.AnyOf) + if len(members) == 0 { + return "" + } + + // anyOf types only need encoding/json (not fmt like oneOf) + gen.AddJSONImport() + + doc := extractDescription(desc.Schema) + code := GenerateUnionType(desc.ShortName, members, false, doc) + + marshalCode := GenerateUnionMarshalAnyOf(desc.ShortName, members) + unmarshalCode := GenerateUnionUnmarshalAnyOf(desc.ShortName, members) + applyDefaultsCode := GenerateUnionApplyDefaults(desc.ShortName, members) + + code += "\n" + marshalCode + "\n" + unmarshalCode + "\n" + applyDefaultsCode + + return code +} + +// generateOneOfType generates a union type for oneOf schemas. +func generateOneOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { + members := collectUnionMembers(gen, desc, desc.OneOf, desc.Schema.OneOf) + if len(members) == 0 { + return "" + } + + // Union types need encoding/json and fmt for marshal/unmarshal + gen.AddJSONImports() + + doc := extractDescription(desc.Schema) + code := GenerateUnionType(desc.ShortName, members, true, doc) + + marshalCode := GenerateUnionMarshalOneOf(desc.ShortName, members) + unmarshalCode := GenerateUnionUnmarshalOneOf(desc.ShortName, members) + applyDefaultsCode := GenerateUnionApplyDefaults(desc.ShortName, members) + + code += "\n" + marshalCode + "\n" + unmarshalCode + "\n" + applyDefaultsCode + + return code +} + +// loadCustomType loads a custom type template and returns its code and imports. +func loadCustomType(templateName string) (string, map[string]string) { + // Lookup the type definition + typeName := strings.TrimSuffix(templateName, ".tmpl") + + // Map template name to type info from registry + var typeDef templates.TypeTemplate + var found bool + + for name, def := range templates.TypeTemplates { + if def.Template == "types/"+templateName || strings.ToLower(name) == typeName { + typeDef = def + found = true + break + } + } + + if !found { + return "", nil + } + + // Read the template file + content, err := templates.TemplateFS.ReadFile("files/" + typeDef.Template) + if err != nil { + return "", nil + } + + // Remove the template comment header + code := string(content) + if idx := strings.Index(code, "}}"); idx != -1 { + code = strings.TrimLeft(code[idx+2:], "\n") + } + + // Build imports map + imports := make(map[string]string) + for _, imp := range typeDef.Imports { + imports[imp.Path] = imp.Alias + } + + return code, imports +} + +// schemaHasApplyDefaults returns true if the schema will have an ApplyDefaults method generated. +// This is true for: +// - Object types with properties +// - Union types (oneOf/anyOf) +// - AllOf types (merged structs) +// This is false for: +// - Primitive types (string, integer, boolean, number) +// - Enum types (without object properties) +// - Arrays +// - Maps (additionalProperties only) +func schemaHasApplyDefaults(schema *base.Schema) bool { + if schema == nil { + return false + } + + // Has properties -> object type with ApplyDefaults + if schema.Properties != nil && schema.Properties.Len() > 0 { + return true + } + + // Has oneOf/anyOf -> union type with ApplyDefaults + if len(schema.OneOf) > 0 || len(schema.AnyOf) > 0 { + return true + } + + // Has allOf -> merged struct with ApplyDefaults + if len(schema.AllOf) > 0 { + return true + } + + return false +} + +// collectUnionMembers gathers union member information for anyOf/oneOf. +func collectUnionMembers(gen *TypeGenerator, parentDesc *SchemaDescriptor, memberDescs []*SchemaDescriptor, memberProxies []*base.SchemaProxy) []UnionMember { + var members []UnionMember + + // Build a map of schema paths to descriptors for lookup + descByPath := make(map[string]*SchemaDescriptor) + for _, desc := range memberDescs { + if desc != nil { + descByPath[desc.Path.String()] = desc + } + } + + for i, proxy := range memberProxies { + var memberType string + var fieldName string + var hasApplyDefaults bool + + if proxy.IsReference() { + ref := proxy.GetReference() + if target, ok := gen.schemaIndex[ref]; ok { + memberType = target.ShortName + fieldName = target.ShortName + hasApplyDefaults = schemaHasApplyDefaults(target.Schema) + } else { + continue + } + } else { + // Check if this inline schema has a descriptor + schema := proxy.Schema() + if schema == nil { + continue + } + + // Determine the path for this member to look up its descriptor + var memberPath SchemaPath + if parentDesc != nil { + // Try to find a descriptor by constructing the expected path + memberPath = parentDesc.Path.Append("anyOf", fmt.Sprintf("%d", i)) + if _, ok := descByPath[memberPath.String()]; !ok { + memberPath = parentDesc.Path.Append("oneOf", fmt.Sprintf("%d", i)) + } + } + + if desc, ok := descByPath[memberPath.String()]; ok && desc.ShortName != "" { + memberType = desc.ShortName + fieldName = desc.ShortName + hasApplyDefaults = schemaHasApplyDefaults(desc.Schema) + } else { + // This is a primitive type that doesn't have a named type + goType := gen.goTypeForSchema(schema, nil) + memberType = goType + // Create a field name based on the type + fieldName = gen.converter.ToTypeName(goType) + fmt.Sprintf("%d", i) + hasApplyDefaults = false // Primitive types don't have ApplyDefaults + } + } + + members = append(members, UnionMember{ + FieldName: fieldName, + TypeName: memberType, + Index: i, + HasApplyDefaults: hasApplyDefaults, + }) + } + + return members +} diff --git a/experimental/internal/codegen/configuration.go b/experimental/internal/codegen/configuration.go new file mode 100644 index 0000000000..c8d1b87388 --- /dev/null +++ b/experimental/internal/codegen/configuration.go @@ -0,0 +1,317 @@ +package codegen + +import ( + "crypto/sha256" + "encoding/hex" + "regexp" + "sort" + "strings" +) + +type Configuration struct { + // PackageName which will be used in all generated files + PackageName string `yaml:"package"` + // Output specifies the output file path + Output string `yaml:"output"` + // Generation controls which parts of the code are generated + Generation GenerationOptions `yaml:"generation,omitempty"` + // TypeMapping allows customizing OpenAPI type/format to Go type mappings + TypeMapping TypeMapping `yaml:"type-mapping,omitempty"` + // NameMangling configures how OpenAPI names are converted to Go identifiers + NameMangling NameMangling `yaml:"name-mangling,omitempty"` + // NameSubstitutions allows direct overrides of generated names + NameSubstitutions NameSubstitutions `yaml:"name-substitutions,omitempty"` + // ImportMapping maps external spec file paths to Go package import paths. + // Example: {"../common/api.yaml": "github.com/org/project/common"} + // Use "-" as the value to indicate types should be in the current package. + ImportMapping map[string]string `yaml:"import-mapping,omitempty"` + // ContentTypes is a list of regexp patterns for media types to generate models for. + // Only request/response bodies with matching content types will have types generated. + // Defaults to common JSON and YAML types if not specified. + ContentTypes []string `yaml:"content-types,omitempty"` + // ContentTypeShortNames maps content type regex patterns to short names for use in type names. + // Example: {"^application/json$": "JSON", "^application/xml$": "XML"} + // These are used when generating response/request type names like "FindPetsJSONResponse". + ContentTypeShortNames []ContentTypeShortName `yaml:"content-type-short-names,omitempty"` + // StructTags configures how struct tags are generated for fields. + // By default, only json tags are generated. + StructTags StructTagsConfig `yaml:"struct-tags,omitempty"` +} + +// ModelsPackage specifies an external package containing the model types. +type ModelsPackage struct { + // Path is the import path for the models package (e.g., "github.com/org/project/models") + Path string `yaml:"path"` + // Alias is an optional import alias. If empty, the last segment of the path is used. + Alias string `yaml:"alias,omitempty"` +} + +// Name returns the package name/alias to use for qualifying types. +// Returns the Alias if set, otherwise derives from the Path. +func (m *ModelsPackage) Name() string { + if m == nil || m.Path == "" { + return "" + } + if m.Alias != "" { + return m.Alias + } + // Derive from path - take last segment + parts := strings.Split(m.Path, "/") + return parts[len(parts)-1] +} + +// Prefix returns the package prefix for qualifying types (e.g., "models."). +// Returns empty string if models are in the same package. +func (m *ModelsPackage) Prefix() string { + name := m.Name() + if name == "" { + return "" + } + return name + "." +} + +// ContentTypeShortName maps a content type pattern to a short name. +type ContentTypeShortName struct { + // Pattern is a regex pattern to match against content types + Pattern string `yaml:"pattern"` + // ShortName is the short name to use in generated type names (e.g., "JSON", "XML") + ShortName string `yaml:"short-name"` +} + +// GenerationOptions controls which parts of the code are generated. +type GenerationOptions struct { + // Server specifies which server framework to generate code for. + // Supported values: "std-http" + // Empty string (default) means no server code is generated. + Server string `yaml:"server,omitempty"` + + // Client enables generation of the HTTP client. + // When true, generates a base Client that returns *http.Response. + Client bool `yaml:"client,omitempty"` + + // SimpleClient enables generation of the SimpleClient wrapper. + // SimpleClient wraps the base Client with typed responses for + // operations that have unambiguous response types. + // Requires Client to also be enabled. + SimpleClient bool `yaml:"simple-client,omitempty"` + + // WebhookInitiator enables generation of webhook initiator code (sends webhook requests). + // Generates a framework-agnostic client that takes the full target URL per-call. + WebhookInitiator bool `yaml:"webhook-initiator,omitempty"` + + // WebhookReceiver enables generation of webhook receiver code (receives webhook requests). + // Generates framework-specific handler functions. Requires Server to be set. + WebhookReceiver bool `yaml:"webhook-receiver,omitempty"` + + // CallbackInitiator enables generation of callback initiator code (sends callback requests). + // Generates a framework-agnostic client that takes the full target URL per-call. + CallbackInitiator bool `yaml:"callback-initiator,omitempty"` + + // CallbackReceiver enables generation of callback receiver code (receives callback requests). + // Generates framework-specific handler functions. Requires Server to be set. + CallbackReceiver bool `yaml:"callback-receiver,omitempty"` + + // ModelsPackage specifies an external package containing the model types. + // When set, models are NOT generated locally - instead, generated code + // imports and references types from this package. + // Example: {path: "github.com/org/project/models"} + ModelsPackage *ModelsPackage `yaml:"models-package,omitempty"` +} + +// ServerType constants for supported server frameworks. +const ( + ServerTypeStdHTTP = "std-http" + ServerTypeChi = "chi" + ServerTypeEcho = "echo" + ServerTypeEchoV4 = "echo/v4" + ServerTypeGin = "gin" + ServerTypeGorilla = "gorilla" + ServerTypeFiber = "fiber" + ServerTypeIris = "iris" +) + +// DefaultContentTypes returns the default list of content type patterns. +// These match common JSON and YAML media types. +func DefaultContentTypes() []string { + return []string{ + `^application/json$`, + `^application/.*\+json$`, + } +} + +// DefaultContentTypeShortNames returns the default content type to short name mappings. +func DefaultContentTypeShortNames() []ContentTypeShortName { + return []ContentTypeShortName{ + {Pattern: `^application/json$`, ShortName: "JSON"}, + {Pattern: `^application/.*\+json$`, ShortName: "JSON"}, + {Pattern: `^application/xml$`, ShortName: "XML"}, + {Pattern: `^application/.*\+xml$`, ShortName: "XML"}, + {Pattern: `^text/xml$`, ShortName: "XML"}, + {Pattern: `^text/plain$`, ShortName: "Text"}, + {Pattern: `^text/html$`, ShortName: "HTML"}, + {Pattern: `^application/octet-stream$`, ShortName: "Binary"}, + {Pattern: `^multipart/form-data$`, ShortName: "Multipart"}, + {Pattern: `^application/x-www-form-urlencoded$`, ShortName: "Form"}, + } +} + +// ApplyDefaults merges user configuration on top of default values. +func (c *Configuration) ApplyDefaults() { + c.TypeMapping = DefaultTypeMapping.Merge(c.TypeMapping) + c.NameMangling = DefaultNameMangling().Merge(c.NameMangling) + if len(c.ContentTypes) == 0 { + c.ContentTypes = DefaultContentTypes() + } + if len(c.ContentTypeShortNames) == 0 { + c.ContentTypeShortNames = DefaultContentTypeShortNames() + } + c.StructTags = DefaultStructTagsConfig().Merge(c.StructTags) +} + +// ContentTypeMatcher checks if content types match configured patterns. +type ContentTypeMatcher struct { + patterns []*regexp.Regexp +} + +// NewContentTypeMatcher creates a matcher from a list of regexp patterns. +// Invalid patterns are silently ignored. +func NewContentTypeMatcher(patterns []string) *ContentTypeMatcher { + m := &ContentTypeMatcher{ + patterns: make([]*regexp.Regexp, 0, len(patterns)), + } + for _, p := range patterns { + if re, err := regexp.Compile(p); err == nil { + m.patterns = append(m.patterns, re) + } + } + return m +} + +// Matches returns true if the content type matches any of the configured patterns. +func (m *ContentTypeMatcher) Matches(contentType string) bool { + for _, re := range m.patterns { + if re.MatchString(contentType) { + return true + } + } + return false +} + +// ContentTypeShortNamer resolves content types to short names for use in type names. +type ContentTypeShortNamer struct { + patterns []*regexp.Regexp + shortNames []string +} + +// NewContentTypeShortNamer creates a short namer from configuration. +func NewContentTypeShortNamer(mappings []ContentTypeShortName) *ContentTypeShortNamer { + n := &ContentTypeShortNamer{ + patterns: make([]*regexp.Regexp, 0, len(mappings)), + shortNames: make([]string, 0, len(mappings)), + } + for _, m := range mappings { + if re, err := regexp.Compile(m.Pattern); err == nil { + n.patterns = append(n.patterns, re) + n.shortNames = append(n.shortNames, m.ShortName) + } + } + return n +} + +// ShortName returns the short name for a content type, or a fallback derived from the content type. +func (n *ContentTypeShortNamer) ShortName(contentType string) string { + for i, re := range n.patterns { + if re.MatchString(contentType) { + return n.shortNames[i] + } + } + // Fallback: derive from content type (e.g., "application/vnd.api+json" -> "VndApiJson") + return deriveContentTypeShortName(contentType) +} + +// deriveContentTypeShortName creates a short name from an unmatched content type. +func deriveContentTypeShortName(contentType string) string { + // Remove "application/", "text/", etc. prefix + if idx := strings.Index(contentType, "/"); idx >= 0 { + contentType = contentType[idx+1:] + } + // Replace non-alphanumeric with spaces for word splitting + var result strings.Builder + capitalizeNext := true + for _, r := range contentType { + if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' { + if capitalizeNext { + if r >= 'a' && r <= 'z' { + r = r - 'a' + 'A' + } + capitalizeNext = false + } + result.WriteRune(r) + } else { + capitalizeNext = true + } + } + return result.String() +} + +// ExternalImport represents an external package import with its alias. +type ExternalImport struct { + Alias string // Short alias for use in generated code (e.g., "ext_a1b2c3") + Path string // Full import path (e.g., "github.com/org/project/common") +} + +// ImportResolver resolves external references to Go package imports. +type ImportResolver struct { + mapping map[string]ExternalImport // spec file path -> import info +} + +// NewImportResolver creates an ImportResolver from the configuration's import mapping. +func NewImportResolver(importMapping map[string]string) *ImportResolver { + resolver := &ImportResolver{ + mapping: make(map[string]ExternalImport), + } + + for specPath, pkgPath := range importMapping { + if pkgPath == "-" { + // "-" means current package, no import needed + resolver.mapping[specPath] = ExternalImport{Alias: "", Path: ""} + } else { + resolver.mapping[specPath] = ExternalImport{ + Alias: hashImportAlias(pkgPath), + Path: pkgPath, + } + } + } + + return resolver +} + +// Resolve looks up an external spec file path and returns its import info. +// Returns nil if the path is not in the mapping. +func (r *ImportResolver) Resolve(specPath string) *ExternalImport { + if imp, ok := r.mapping[specPath]; ok { + return &imp + } + return nil +} + +// AllImports returns all external imports sorted by alias. +func (r *ImportResolver) AllImports() []ExternalImport { + var imports []ExternalImport + for _, imp := range r.mapping { + if imp.Path != "" { // Skip current package markers + imports = append(imports, imp) + } + } + sort.Slice(imports, func(i, j int) bool { + return imports[i].Alias < imports[j].Alias + }) + return imports +} + +// hashImportAlias generates a short, deterministic alias from an import path. +// Uses first 8 characters of SHA256 hash prefixed with "ext_". +func hashImportAlias(importPath string) string { + h := sha256.Sum256([]byte(importPath)) + return "ext_" + hex.EncodeToString(h[:])[:8] +} diff --git a/experimental/internal/codegen/configuration_test.go b/experimental/internal/codegen/configuration_test.go new file mode 100644 index 0000000000..700c65505a --- /dev/null +++ b/experimental/internal/codegen/configuration_test.go @@ -0,0 +1,152 @@ +package codegen + +import ( + "testing" + + "gopkg.in/yaml.v3" +) + +func TestContentTypeMatcher(t *testing.T) { + tests := []struct { + name string + patterns []string + contentType string + want bool + }{ + // Default patterns - JSON only (YAML not supported without custom unmarshalers) + {"json exact", DefaultContentTypes(), "application/json", true}, + {"json+suffix", DefaultContentTypes(), "application/vnd.api+json", true}, + {"problem+json", DefaultContentTypes(), "application/problem+json", true}, + + // YAML not in defaults (would need custom unmarshalers) + {"yaml not default", DefaultContentTypes(), "application/yaml", false}, + {"text/yaml not default", DefaultContentTypes(), "text/yaml", false}, + + // Non-matching + {"text/plain", DefaultContentTypes(), "text/plain", false}, + {"text/html", DefaultContentTypes(), "text/html", false}, + {"application/xml", DefaultContentTypes(), "application/xml", false}, + {"application/octet-stream", DefaultContentTypes(), "application/octet-stream", false}, + {"multipart/form-data", DefaultContentTypes(), "multipart/form-data", false}, + {"image/png", DefaultContentTypes(), "image/png", false}, + + // Custom patterns + {"custom xml", []string{`^application/xml$`}, "application/xml", true}, + {"custom xml no match", []string{`^application/xml$`}, "application/json", false}, + {"custom wildcard", []string{`^text/.*`}, "text/plain", true}, + {"custom wildcard html", []string{`^text/.*`}, "text/html", true}, + {"custom yaml", []string{`^application/yaml$`}, "application/yaml", true}, + + // Empty patterns + {"empty patterns", []string{}, "application/json", false}, + + // Invalid pattern (silently ignored) + {"invalid pattern", []string{`[invalid`}, "application/json", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := NewContentTypeMatcher(tt.patterns) + got := m.Matches(tt.contentType) + if got != tt.want { + t.Errorf("Matches(%q) = %v, want %v", tt.contentType, got, tt.want) + } + }) + } +} + +func TestDefaultContentTypes(t *testing.T) { + defaults := DefaultContentTypes() + if len(defaults) == 0 { + t.Error("DefaultContentTypes() returned empty slice") + } + + // Verify all patterns are valid regexps + m := NewContentTypeMatcher(defaults) + if len(m.patterns) != len(defaults) { + t.Errorf("Some default patterns failed to compile: got %d patterns, want %d", + len(m.patterns), len(defaults)) + } +} + +func TestGenerationOptions_ServerYAML(t *testing.T) { + t.Run("unmarshal server field", func(t *testing.T) { + yamlContent := ` +generation: + server: std-http +` + var cfg Configuration + err := yaml.Unmarshal([]byte(yamlContent), &cfg) + if err != nil { + t.Fatalf("yaml.Unmarshal failed: %v", err) + } + if cfg.Generation.Server != ServerTypeStdHTTP { + t.Errorf("Server = %q, want %q", cfg.Generation.Server, ServerTypeStdHTTP) + } + }) + + t.Run("unmarshal empty server field", func(t *testing.T) { + yamlContent := ` +generation: + no-models: true +` + var cfg Configuration + err := yaml.Unmarshal([]byte(yamlContent), &cfg) + if err != nil { + t.Fatalf("yaml.Unmarshal failed: %v", err) + } + if cfg.Generation.Server != "" { + t.Errorf("Server = %q, want empty string", cfg.Generation.Server) + } + }) + + t.Run("marshal server field", func(t *testing.T) { + cfg := Configuration{ + PackageName: "test", + Generation: GenerationOptions{ + Server: ServerTypeStdHTTP, + }, + } + data, err := yaml.Marshal(&cfg) + if err != nil { + t.Fatalf("yaml.Marshal failed: %v", err) + } + if got := string(data); !contains(got, "server: std-http") { + t.Errorf("Marshaled YAML does not contain 'server: std-http':\n%s", got) + } + }) + + t.Run("omit empty server field", func(t *testing.T) { + cfg := Configuration{ + PackageName: "test", + Generation: GenerationOptions{}, + } + data, err := yaml.Marshal(&cfg) + if err != nil { + t.Fatalf("yaml.Marshal failed: %v", err) + } + if got := string(data); contains(got, "server:") { + t.Errorf("Marshaled YAML should not contain 'server:' when empty:\n%s", got) + } + }) +} + +func TestServerTypeConstants(t *testing.T) { + if ServerTypeStdHTTP != "std-http" { + t.Errorf("ServerTypeStdHTTP = %q, want %q", ServerTypeStdHTTP, "std-http") + } +} + +// contains is a simple helper for string containment check +func contains(s, substr string) bool { + return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsAt(s, substr)) +} + +func containsAt(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} diff --git a/experimental/internal/codegen/extension.go b/experimental/internal/codegen/extension.go new file mode 100644 index 0000000000..f3f48dcbb3 --- /dev/null +++ b/experimental/internal/codegen/extension.go @@ -0,0 +1,337 @@ +// Package codegen provides extension handling for OpenAPI x- properties. +package codegen + +import ( + "fmt" + "strings" + + "github.com/pb33f/libopenapi/orderedmap" + "go.yaml.in/yaml/v4" +) + +// Extension names - new naming convention with x-oapi-codegen- prefix +const ( + // ExtTypeOverride specifies an external type to use instead of generating one. + // Format: "TypeName" or "TypeName;import/path" or "TypeName;alias import/path" + ExtTypeOverride = "x-oapi-codegen-type-override" + + // ExtNameOverride overrides the generated field name. + ExtNameOverride = "x-oapi-codegen-name-override" + + // ExtTypeNameOverride overrides the generated type name. + ExtTypeNameOverride = "x-oapi-codegen-type-name-override" + + // ExtSkipOptionalPointer skips pointer wrapping for optional fields. + ExtSkipOptionalPointer = "x-oapi-codegen-skip-optional-pointer" + + // ExtJSONIgnore excludes the field from JSON marshaling (json:"-"). + ExtJSONIgnore = "x-oapi-codegen-json-ignore" + + // ExtOmitEmpty explicitly controls the omitempty JSON tag. + ExtOmitEmpty = "x-oapi-codegen-omitempty" + + // ExtOmitZero adds omitzero to the JSON tag (Go 1.24+ encoding/json/v2). + ExtOmitZero = "x-oapi-codegen-omitzero" + + // ExtEnumVarNames overrides the generated enum constant names. + ExtEnumVarNames = "x-oapi-codegen-enum-varnames" + + // ExtDeprecatedReason provides a deprecation reason for documentation. + ExtDeprecatedReason = "x-oapi-codegen-deprecated-reason" + + // ExtOrder controls field ordering in generated structs. + ExtOrder = "x-oapi-codegen-order" +) + +// Legacy extension names for backwards compatibility +const ( + legacyExtGoType = "x-go-type" + legacyExtGoTypeImport = "x-go-type-import" + legacyExtGoName = "x-go-name" + legacyExtGoTypeName = "x-go-type-name" + legacyExtGoTypeSkipOptionalPtr = "x-go-type-skip-optional-pointer" + legacyExtGoJSONIgnore = "x-go-json-ignore" + legacyExtOmitEmpty = "x-omitempty" + legacyExtOmitZero = "x-omitzero" + legacyExtEnumVarNames = "x-enum-varnames" + legacyExtEnumNames = "x-enumNames" // Alternative name + legacyExtDeprecatedReason = "x-deprecated-reason" + legacyExtOrder = "x-order" +) + +// TypeOverride represents an external type override with optional import. +type TypeOverride struct { + TypeName string // The Go type name (e.g., "uuid.UUID") + ImportPath string // Import path (e.g., "github.com/google/uuid") + ImportAlias string // Optional import alias (e.g., "foo" for `import foo "..."`) +} + +// Extensions holds parsed extension values for a schema or property. +type Extensions struct { + TypeOverride *TypeOverride // External type to use + NameOverride string // Override field name + TypeNameOverride string // Override generated type name + SkipOptionalPointer *bool // Skip pointer for optional fields + JSONIgnore *bool // Exclude from JSON + OmitEmpty *bool // Control omitempty + OmitZero *bool // Control omitzero + EnumVarNames []string // Override enum constant names + DeprecatedReason string // Deprecation reason + Order *int // Field ordering +} + +// ParseExtensions extracts extension values from a schema's extensions map. +// It supports both new (x-oapi-codegen-*) and legacy (x-go-*) extension names, +// logging deprecation warnings for legacy names. +func ParseExtensions(extensions *orderedmap.Map[string, *yaml.Node], path string) (*Extensions, error) { + if extensions == nil { + return &Extensions{}, nil + } + + ext := &Extensions{} + + // Legacy type override needs special handling: x-go-type and x-go-type-import + // are separate extensions that must be combined + var legacyGoType string + var legacyGoTypeImport any + + for pair := extensions.First(); pair != nil; pair = pair.Next() { + key := pair.Key() + node := pair.Value() + if node == nil { + continue + } + + val := decodeYAMLNode(node) + + switch key { + case ExtTypeOverride: + override, err := parseTypeOverride(val) + if err != nil { + return nil, fmt.Errorf("parsing %s: %w", key, err) + } + ext.TypeOverride = override + + case legacyExtGoType: + if s, ok := val.(string); ok { + legacyGoType = s + } + + case legacyExtGoTypeImport: + legacyGoTypeImport = val + + case ExtNameOverride, legacyExtGoName: + s, err := asString(val, key) + if err != nil { + return nil, err + } + ext.NameOverride = s + + case ExtTypeNameOverride, legacyExtGoTypeName: + s, err := asString(val, key) + if err != nil { + return nil, err + } + ext.TypeNameOverride = s + + case ExtSkipOptionalPointer, legacyExtGoTypeSkipOptionalPtr: + b, err := asBool(val, key) + if err != nil { + return nil, err + } + ext.SkipOptionalPointer = &b + + case ExtJSONIgnore, legacyExtGoJSONIgnore: + b, err := asBool(val, key) + if err != nil { + return nil, err + } + ext.JSONIgnore = &b + + case ExtOmitEmpty, legacyExtOmitEmpty: + b, err := asBool(val, key) + if err != nil { + return nil, err + } + ext.OmitEmpty = &b + + case ExtOmitZero, legacyExtOmitZero: + b, err := asBool(val, key) + if err != nil { + return nil, err + } + ext.OmitZero = &b + + case ExtEnumVarNames, legacyExtEnumVarNames, legacyExtEnumNames: + s, err := asStringSlice(val, key) + if err != nil { + return nil, err + } + ext.EnumVarNames = s + + case ExtDeprecatedReason, legacyExtDeprecatedReason: + s, err := asString(val, key) + if err != nil { + return nil, err + } + ext.DeprecatedReason = s + + case ExtOrder, legacyExtOrder: + i, err := asInt(val, key) + if err != nil { + return nil, err + } + ext.Order = &i + + default: + // Unknown extension - ignore + } + } + + // Combine legacy x-go-type and x-go-type-import if no new-style override was set + if ext.TypeOverride == nil && legacyGoType != "" { + ext.TypeOverride = buildLegacyTypeOverride(legacyGoType, legacyGoTypeImport) + } + + return ext, nil +} + +// hasExtension checks if an extension exists by either the new or legacy name. +// This is used to check for extensions before fully parsing them. +func hasExtension(extensions *orderedmap.Map[string, *yaml.Node], newName, legacyName string) bool { + if extensions == nil { + return false + } + + for pair := extensions.First(); pair != nil; pair = pair.Next() { + key := pair.Key() + if key == newName || key == legacyName { + return true + } + } + return false +} + +// decodeYAMLNode converts a yaml.Node to a Go value. +func decodeYAMLNode(node *yaml.Node) any { + if node == nil { + return nil + } + + var result any + if err := node.Decode(&result); err != nil { + return nil + } + return result +} + +// parseTypeOverride parses the new combined type override format. +// Format: "TypeName" or "TypeName;import/path" or "TypeName;alias import/path" +func parseTypeOverride(val any) (*TypeOverride, error) { + str, ok := val.(string) + if !ok { + return nil, fmt.Errorf("expected string, got %T", val) + } + + override := &TypeOverride{} + parts := strings.SplitN(str, ";", 2) + override.TypeName = strings.TrimSpace(parts[0]) + + if len(parts) == 2 { + importPart := strings.TrimSpace(parts[1]) + importParts := strings.SplitN(importPart, " ", 2) + if len(importParts) == 2 { + override.ImportAlias = strings.TrimSpace(importParts[0]) + override.ImportPath = strings.TrimSpace(importParts[1]) + } else { + override.ImportPath = importPart + } + } + + return override, nil +} + +// buildLegacyTypeOverride combines legacy x-go-type and x-go-type-import values. +func buildLegacyTypeOverride(typeName string, importVal any) *TypeOverride { + override := &TypeOverride{ + TypeName: typeName, + } + + if importVal == nil { + return override + } + + // Legacy import can be a string or an object with path/name + switch v := importVal.(type) { + case string: + override.ImportPath = v + case map[string]any: + if p, ok := v["path"].(string); ok { + override.ImportPath = p + } + if name, ok := v["name"].(string); ok { + override.ImportAlias = name + } + } + + return override +} + +// Type conversion helpers that include the extension name in error messages + +func asString(val any, extName string) (string, error) { + if val == nil { + return "", nil + } + str, ok := val.(string) + if !ok { + return "", fmt.Errorf("parsing %s: expected string, got %T", extName, val) + } + return str, nil +} + +func asBool(val any, extName string) (bool, error) { + if val == nil { + return false, nil + } + b, ok := val.(bool) + if !ok { + return false, fmt.Errorf("parsing %s: expected bool, got %T", extName, val) + } + return b, nil +} + +func asInt(val any, extName string) (int, error) { + if val == nil { + return 0, nil + } + switch v := val.(type) { + case int: + return v, nil + case int64: + return int(v), nil + case float64: + return int(v), nil + default: + return 0, fmt.Errorf("parsing %s: expected int, got %T", extName, val) + } +} + +func asStringSlice(val any, extName string) ([]string, error) { + if val == nil { + return nil, nil + } + slice, ok := val.([]any) + if !ok { + return nil, fmt.Errorf("parsing %s: expected array, got %T", extName, val) + } + result := make([]string, len(slice)) + for i, v := range slice { + str, ok := v.(string) + if !ok { + return nil, fmt.Errorf("parsing %s: expected string at index %d, got %T", extName, i, v) + } + result[i] = str + } + return result, nil +} diff --git a/experimental/internal/codegen/extension_integration_test.go b/experimental/internal/codegen/extension_integration_test.go new file mode 100644 index 0000000000..c100af7333 --- /dev/null +++ b/experimental/internal/codegen/extension_integration_test.go @@ -0,0 +1,201 @@ +package codegen + +import ( + "strings" + "testing" + + "github.com/pb33f/libopenapi" +) + +func TestExtensionIntegration(t *testing.T) { + spec := ` +openapi: "3.1.0" +info: + title: Extension Test API + version: "1.0" +paths: {} +components: + schemas: + # Test type-name-override + MySchema: + type: object + x-oapi-codegen-type-name-override: CustomTypeName + properties: + id: + type: string + + # Test type-override at schema level + ExternalType: + type: string + x-oapi-codegen-type-override: "uuid.UUID;github.com/google/uuid" + + # Test field-level extensions + User: + type: object + properties: + # Test name override + user_id: + type: string + x-oapi-codegen-name-override: UserID + # Test type override + created_at: + type: string + x-oapi-codegen-type-override: "time.Time;time" + # Test skip optional pointer + description: + type: string + x-oapi-codegen-skip-optional-pointer: true + # Test omitempty control + status: + type: string + x-oapi-codegen-omitempty: false + # Test omitzero + count: + type: integer + x-oapi-codegen-omitzero: true + # Test order (count should come before status) + age: + type: integer + x-oapi-codegen-order: 1 + name: + type: string + x-oapi-codegen-order: 0 + # Test deprecated reason + old_field: + type: string + x-oapi-codegen-deprecated-reason: "Use new_field instead" + + # Test enum with custom var names + Status: + type: string + enum: + - active + - inactive + - pending + x-oapi-codegen-enum-varnames: + - Active + - Inactive + - Pending +` + + doc, err := libopenapi.NewDocument([]byte(spec)) + if err != nil { + t.Fatalf("Failed to parse spec: %v", err) + } + + cfg := Configuration{ + PackageName: "output", + } + + code, err := Generate(doc, nil, cfg) + if err != nil { + t.Fatalf("Generate failed: %v", err) + } + + t.Logf("Generated code:\n%s", code) + + // Verify type-name-override + if !strings.Contains(code, "type CustomTypeName") { + t.Error("Expected CustomTypeName type from type-name-override") + } + + // Verify type-override at schema level creates alias + if !strings.Contains(code, "= uuid.UUID") { + t.Error("Expected type alias to uuid.UUID from type-override") + } + if !strings.Contains(code, `"github.com/google/uuid"`) { + t.Error("Expected uuid import") + } + + // Verify name override + if !strings.Contains(code, "UserID") { + t.Error("Expected UserID field from name-override") + } + + // Verify type override on field + if !strings.Contains(code, "time.Time") { + t.Error("Expected time.Time from field type-override") + } + if !strings.Contains(code, `"time"`) { + t.Error("Expected time import") + } + + // Verify skip-optional-pointer (description should be string, not *string) + // The field should appear as just "string", not "*string" + if strings.Contains(code, "Description *string") || strings.Contains(code, "Description *string") { + t.Error("Expected description to not be a pointer due to skip-optional-pointer") + } + if !strings.Contains(code, "Description string") && !strings.Contains(code, "Description string") { + t.Error("Expected description to be a non-pointer string") + } + + // Verify omitzero + if !strings.Contains(code, "omitzero") { + t.Error("Expected omitzero in struct tags") + } + + // Verify deprecated reason in doc + if !strings.Contains(code, "Deprecated:") { + t.Error("Expected Deprecated: in documentation") + } + + // Verify enum with custom var names + if !strings.Contains(code, "Status_Active") { + t.Error("Expected Status_Active from custom enum var names") + } + if !strings.Contains(code, "Status_Inactive") { + t.Error("Expected Status_Inactive from custom enum var names") + } + if !strings.Contains(code, "Status_Pending") { + t.Error("Expected Status_Pending from custom enum var names") + } +} + +func TestLegacyExtensionIntegration(t *testing.T) { + spec := ` +openapi: "3.1.0" +info: + title: Legacy Extension Test API + version: "1.0" +paths: {} +components: + schemas: + User: + type: object + properties: + # Test legacy x-go-type + id: + type: string + x-go-type: mypackage.ID + # Test legacy x-go-name + user_name: + type: string + x-go-name: Username +` + + doc, err := libopenapi.NewDocument([]byte(spec)) + if err != nil { + t.Fatalf("Failed to parse spec: %v", err) + } + + cfg := Configuration{ + PackageName: "output", + } + + code, err := Generate(doc, nil, cfg) + if err != nil { + t.Fatalf("Generate failed: %v", err) + } + + t.Logf("Generated code:\n%s", code) + + // Verify legacy x-go-type works + if !strings.Contains(code, "mypackage.ID") { + t.Error("Expected mypackage.ID from legacy x-go-type") + } + + // Verify legacy x-go-name works + if !strings.Contains(code, "Username") { + t.Error("Expected Username from legacy x-go-name") + } +} diff --git a/experimental/internal/codegen/extension_test.go b/experimental/internal/codegen/extension_test.go new file mode 100644 index 0000000000..c0f615fc41 --- /dev/null +++ b/experimental/internal/codegen/extension_test.go @@ -0,0 +1,180 @@ +package codegen + +import ( + "testing" + + "github.com/pb33f/libopenapi/orderedmap" + "go.yaml.in/yaml/v4" +) + +func TestParseTypeOverride(t *testing.T) { + tests := []struct { + name string + input string + wantType string + wantPath string + wantAlias string + }{ + { + name: "simple type", + input: "int64", + wantType: "int64", + }, + { + name: "type with import", + input: "uuid.UUID;github.com/google/uuid", + wantType: "uuid.UUID", + wantPath: "github.com/google/uuid", + }, + { + name: "type with aliased import", + input: "foo.Type;foo github.com/bar/foo/v2", + wantType: "foo.Type", + wantPath: "github.com/bar/foo/v2", + wantAlias: "foo", + }, + { + name: "type with spaces", + input: " decimal.Decimal ; github.com/shopspring/decimal ", + wantType: "decimal.Decimal", + wantPath: "github.com/shopspring/decimal", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseTypeOverride(tt.input) + if err != nil { + t.Fatalf("parseTypeOverride() error = %v", err) + } + if got.TypeName != tt.wantType { + t.Errorf("TypeName = %q, want %q", got.TypeName, tt.wantType) + } + if got.ImportPath != tt.wantPath { + t.Errorf("ImportPath = %q, want %q", got.ImportPath, tt.wantPath) + } + if got.ImportAlias != tt.wantAlias { + t.Errorf("ImportAlias = %q, want %q", got.ImportAlias, tt.wantAlias) + } + }) + } +} + +func TestParseExtensions(t *testing.T) { + // Create a test extensions map + extensions := orderedmap.New[string, *yaml.Node]() + + // Add a type override extension + typeOverrideNode := &yaml.Node{} + typeOverrideNode.SetString("uuid.UUID;github.com/google/uuid") + extensions.Set(ExtTypeOverride, typeOverrideNode) + + // Add a name override extension + nameOverrideNode := &yaml.Node{} + nameOverrideNode.SetString("CustomFieldName") + extensions.Set(ExtNameOverride, nameOverrideNode) + + // Add omitempty extension + omitEmptyNode := &yaml.Node{} + if err := omitEmptyNode.Encode(true); err != nil { + t.Fatalf("Failed to encode omitEmptyNode: %v", err) + } + extensions.Set(ExtOmitEmpty, omitEmptyNode) + + ext, err := ParseExtensions(extensions, "#/test/path") + if err != nil { + t.Fatalf("ParseExtensions() error = %v", err) + } + + // Check type override + if ext.TypeOverride == nil { + t.Fatal("TypeOverride should not be nil") + } + if ext.TypeOverride.TypeName != "uuid.UUID" { + t.Errorf("TypeOverride.TypeName = %q, want %q", ext.TypeOverride.TypeName, "uuid.UUID") + } + if ext.TypeOverride.ImportPath != "github.com/google/uuid" { + t.Errorf("TypeOverride.ImportPath = %q, want %q", ext.TypeOverride.ImportPath, "github.com/google/uuid") + } + + // Check name override + if ext.NameOverride != "CustomFieldName" { + t.Errorf("NameOverride = %q, want %q", ext.NameOverride, "CustomFieldName") + } + + // Check omitempty + if ext.OmitEmpty == nil || *ext.OmitEmpty != true { + t.Errorf("OmitEmpty = %v, want true", ext.OmitEmpty) + } +} + +func TestParseExtensionsLegacy(t *testing.T) { + // Create a test extensions map with legacy names + extensions := orderedmap.New[string, *yaml.Node]() + + // Add legacy x-go-type extension + goTypeNode := &yaml.Node{} + goTypeNode.SetString("time.Time") + extensions.Set("x-go-type", goTypeNode) + + // Add legacy x-go-type-import extension + goImportNode := &yaml.Node{} + goImportNode.SetString("time") + extensions.Set("x-go-type-import", goImportNode) + + // Add legacy x-go-name extension + goNameNode := &yaml.Node{} + goNameNode.SetString("LegacyFieldName") + extensions.Set("x-go-name", goNameNode) + + ext, err := ParseExtensions(extensions, "#/test/path") + if err != nil { + t.Fatalf("ParseExtensions() error = %v", err) + } + + // Check type override (from legacy) + if ext.TypeOverride == nil { + t.Fatal("TypeOverride should not be nil") + } + if ext.TypeOverride.TypeName != "time.Time" { + t.Errorf("TypeOverride.TypeName = %q, want %q", ext.TypeOverride.TypeName, "time.Time") + } + if ext.TypeOverride.ImportPath != "time" { + t.Errorf("TypeOverride.ImportPath = %q, want %q", ext.TypeOverride.ImportPath, "time") + } + + // Check name override (from legacy) + if ext.NameOverride != "LegacyFieldName" { + t.Errorf("NameOverride = %q, want %q", ext.NameOverride, "LegacyFieldName") + } +} + +func TestParseExtensionsEnumVarNames(t *testing.T) { + extensions := orderedmap.New[string, *yaml.Node]() + + // Add enum var names as a sequence + enumNamesNode := &yaml.Node{ + Kind: yaml.SequenceNode, + Content: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "Active"}, + {Kind: yaml.ScalarNode, Value: "Inactive"}, + {Kind: yaml.ScalarNode, Value: "Pending"}, + }, + } + extensions.Set(ExtEnumVarNames, enumNamesNode) + + ext, err := ParseExtensions(extensions, "#/test/path") + if err != nil { + t.Fatalf("ParseExtensions() error = %v", err) + } + + if len(ext.EnumVarNames) != 3 { + t.Fatalf("EnumVarNames length = %d, want 3", len(ext.EnumVarNames)) + } + expected := []string{"Active", "Inactive", "Pending"} + for i, name := range ext.EnumVarNames { + if name != expected[i] { + t.Errorf("EnumVarNames[%d] = %q, want %q", i, name, expected[i]) + } + } +} diff --git a/experimental/internal/codegen/gather.go b/experimental/internal/codegen/gather.go new file mode 100644 index 0000000000..0644ed7897 --- /dev/null +++ b/experimental/internal/codegen/gather.go @@ -0,0 +1,621 @@ +package codegen + +import ( + "fmt" + "log/slog" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel/high/base" + v3 "github.com/pb33f/libopenapi/datamodel/high/v3" +) + +// GatherResult contains the results of gathering from an OpenAPI document. +type GatherResult struct { + Schemas []*SchemaDescriptor + ParamTracker *ParamUsageTracker +} + +// GatherSchemas traverses an OpenAPI document and collects all schemas into a list. +func GatherSchemas(doc libopenapi.Document, contentTypeMatcher *ContentTypeMatcher) ([]*SchemaDescriptor, error) { + result, err := GatherAll(doc, contentTypeMatcher) + if err != nil { + return nil, err + } + return result.Schemas, nil +} + +// GatherAll traverses an OpenAPI document and collects all schemas and parameter usage. +func GatherAll(doc libopenapi.Document, contentTypeMatcher *ContentTypeMatcher) (*GatherResult, error) { + model, err := doc.BuildV3Model() + if err != nil { + return nil, fmt.Errorf("building v3 model: %w", err) + } + if model == nil { + return nil, fmt.Errorf("failed to build v3 model") + } + + g := &gatherer{ + schemas: make([]*SchemaDescriptor, 0), + contentTypeMatcher: contentTypeMatcher, + paramTracker: NewParamUsageTracker(), + } + + g.gatherFromDocument(&model.Model) + return &GatherResult{ + Schemas: g.schemas, + ParamTracker: g.paramTracker, + }, nil +} + +type gatherer struct { + schemas []*SchemaDescriptor + contentTypeMatcher *ContentTypeMatcher + paramTracker *ParamUsageTracker + // Context for the current operation being gathered (for nicer naming) + currentOperationID string + currentContentType string +} + +func (g *gatherer) gatherFromDocument(doc *v3.Document) { + // Gather from components/schemas + if doc.Components != nil && doc.Components.Schemas != nil { + for pair := doc.Components.Schemas.First(); pair != nil; pair = pair.Next() { + name := pair.Key() + schemaProxy := pair.Value() + path := SchemaPath{"components", "schemas", name} + g.gatherFromSchemaProxy(schemaProxy, path, nil) + } + } + + // Gather from paths + if doc.Paths != nil && doc.Paths.PathItems != nil { + for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { + pathStr := pair.Key() + pathItem := pair.Value() + g.gatherFromPathItem(pathItem, SchemaPath{"paths", pathStr}) + } + } + + // Gather from webhooks (3.1+) + if doc.Webhooks != nil { + for pair := doc.Webhooks.First(); pair != nil; pair = pair.Next() { + name := pair.Key() + pathItem := pair.Value() + g.gatherFromPathItem(pathItem, SchemaPath{"webhooks", name}) + } + } +} + +func (g *gatherer) gatherFromPathItem(pathItem *v3.PathItem, basePath SchemaPath) { + if pathItem == nil { + return + } + + // Path-level parameters + for i, param := range pathItem.Parameters { + g.gatherFromParameter(param, basePath.Append("parameters", fmt.Sprintf("%d", i))) + } + + // Operations + ops := pathItem.GetOperations() + if ops != nil { + for pair := ops.First(); pair != nil; pair = pair.Next() { + method := pair.Key() + op := pair.Value() + g.gatherFromOperation(op, basePath.Append(method)) + } + } +} + +func (g *gatherer) gatherFromOperation(op *v3.Operation, basePath SchemaPath) { + if op == nil { + return + } + + // Set operation context for nicer naming + prevOperationID := g.currentOperationID + if op.OperationId != "" { + g.currentOperationID = op.OperationId + } + + // Parameters + for i, param := range op.Parameters { + g.gatherFromParameter(param, basePath.Append("parameters", fmt.Sprintf("%d", i))) + } + + // Request body + if op.RequestBody != nil { + g.gatherFromRequestBody(op.RequestBody, basePath.Append("requestBody")) + } + + // Responses + if op.Responses != nil && op.Responses.Codes != nil { + for pair := op.Responses.Codes.First(); pair != nil; pair = pair.Next() { + code := pair.Key() + response := pair.Value() + g.gatherFromResponse(response, basePath.Append("responses", code)) + } + } + + // Callbacks + if op.Callbacks != nil { + for pair := op.Callbacks.First(); pair != nil; pair = pair.Next() { + name := pair.Key() + callback := pair.Value() + g.gatherFromCallback(callback, basePath.Append("callbacks", name)) + } + } + + // Restore previous operation context + g.currentOperationID = prevOperationID +} + +func (g *gatherer) gatherFromParameter(param *v3.Parameter, basePath SchemaPath) { + if param == nil { + return + } + + // Track parameter styling usage for code generation + if g.paramTracker != nil && param.Schema != nil { + // Determine style (with defaults based on location) + style := param.Style + if style == "" { + style = DefaultParamStyle(param.In) + } + + // Determine explode (with defaults based on location) + explode := DefaultParamExplode(param.In) + if param.Explode != nil { + explode = *param.Explode + } + + // Record both style (client) and bind (server) usage + g.paramTracker.RecordParam(style, explode) + } + + if param.Schema != nil { + g.gatherFromSchemaProxy(param.Schema, basePath.Append("schema"), nil) + } + + // Parameter can also have content with schemas + if param.Content != nil { + for pair := param.Content.First(); pair != nil; pair = pair.Next() { + contentType := pair.Key() + mediaType := pair.Value() + g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) + } + } +} + +func (g *gatherer) gatherFromRequestBody(rb *v3.RequestBody, basePath SchemaPath) { + if rb == nil || rb.Content == nil { + return + } + + for pair := rb.Content.First(); pair != nil; pair = pair.Next() { + contentType := pair.Key() + // Skip content types that don't match the configured patterns + if g.contentTypeMatcher != nil && !g.contentTypeMatcher.Matches(contentType) { + continue + } + // Set content type context + prevContentType := g.currentContentType + g.currentContentType = contentType + + mediaType := pair.Value() + g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) + + g.currentContentType = prevContentType + } +} + +func (g *gatherer) gatherFromResponse(response *v3.Response, basePath SchemaPath) { + if response == nil { + return + } + + if response.Content != nil { + for pair := response.Content.First(); pair != nil; pair = pair.Next() { + contentType := pair.Key() + // Skip content types that don't match the configured patterns + if g.contentTypeMatcher != nil && !g.contentTypeMatcher.Matches(contentType) { + continue + } + // Set content type context + prevContentType := g.currentContentType + g.currentContentType = contentType + + mediaType := pair.Value() + g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) + + g.currentContentType = prevContentType + } + } + + // Response headers can have schemas + if response.Headers != nil { + for pair := response.Headers.First(); pair != nil; pair = pair.Next() { + name := pair.Key() + header := pair.Value() + if header != nil && header.Schema != nil { + g.gatherFromSchemaProxy(header.Schema, basePath.Append("headers", name, "schema"), nil) + } + } + } +} + +func (g *gatherer) gatherFromMediaType(mt *v3.MediaType, basePath SchemaPath) { + if mt == nil || mt.Schema == nil { + return + } + g.gatherFromSchemaProxy(mt.Schema, basePath.Append("schema"), nil) +} + +func (g *gatherer) gatherFromCallback(callback *v3.Callback, basePath SchemaPath) { + if callback == nil || callback.Expression == nil { + return + } + + for pair := callback.Expression.First(); pair != nil; pair = pair.Next() { + expr := pair.Key() + pathItem := pair.Value() + g.gatherFromPathItem(pathItem, basePath.Append(expr)) + } +} + +func (g *gatherer) gatherFromSchemaProxy(proxy *base.SchemaProxy, path SchemaPath, parent *SchemaDescriptor) *SchemaDescriptor { + if proxy == nil { + return nil + } + + // Check if this is a reference + isRef := proxy.IsReference() + ref := "" + if isRef { + ref = proxy.GetReference() + } + + // Get the resolved schema + schema := proxy.Schema() + + // Check if schema has extensions that require type generation + hasTypeOverride := schema != nil && schema.Extensions != nil && hasExtension(schema.Extensions, ExtTypeOverride, legacyExtGoType) + hasTypeNameOverride := schema != nil && schema.Extensions != nil && hasExtension(schema.Extensions, ExtTypeNameOverride, legacyExtGoTypeName) + + // Only gather schemas that need a generated type + // References are always gathered (they point to real schemas) + // Simple types (primitives without enum) are skipped + // Inline nullable primitives (under properties/) don't need types - they use Nullable[T] directly + // Schemas with type-override or type-name-override extensions always need types + isInlineProperty := path.ContainsProperties() + skipInlineNullablePrimitive := isInlineProperty && isNullablePrimitive(schema) + needsType := isRef || needsGeneratedType(schema) || hasTypeOverride || hasTypeNameOverride + if needsType && !skipInlineNullablePrimitive { + desc := &SchemaDescriptor{ + Path: path, + Parent: parent, + Ref: ref, + Schema: schema, + OperationID: g.currentOperationID, + ContentType: g.currentContentType, + } + + // Parse extensions from the schema + if schema != nil && schema.Extensions != nil { + ext, err := ParseExtensions(schema.Extensions, path.String()) + if err != nil { + slog.Warn("failed to parse extensions", + "path", path.String(), + "error", err) + } else { + desc.Extensions = ext + } + } + + g.schemas = append(g.schemas, desc) + + // Don't recurse into references - they point to schemas we'll gather elsewhere + if isRef { + return desc + } + + // Recurse into schema structure + if schema != nil { + g.gatherFromSchema(schema, path, desc) + } + return desc + } else if schema != nil { + // Even if we don't gather this schema, we still need to recurse + // to find any nested complex schemas (e.g., array items that are objects) + g.gatherFromSchema(schema, path, nil) + } + return nil +} + +// gatherSchemaDescriptorOnly creates a descriptor for field extraction without adding it +// to the schemas list (i.e., no type will be generated for it). +// This is used for inline allOf members whose fields are flattened into the parent. +func (g *gatherer) gatherSchemaDescriptorOnly(proxy *base.SchemaProxy, path SchemaPath, parent *SchemaDescriptor) *SchemaDescriptor { + if proxy == nil { + return nil + } + + schema := proxy.Schema() + if schema == nil { + return nil + } + + desc := &SchemaDescriptor{ + Path: path, + Parent: parent, + Schema: schema, + } + + // Parse extensions from the schema + if schema.Extensions != nil { + ext, err := ParseExtensions(schema.Extensions, path.String()) + if err != nil { + slog.Warn("failed to parse extensions", + "path", path.String(), + "error", err) + } else { + desc.Extensions = ext + } + } + + // Still recurse to gather any nested complex schemas that DO need types + // (e.g., nested objects within properties) + g.gatherFromSchema(schema, path, desc) + + return desc +} + +// needsGeneratedType returns true if a schema requires a generated Go type. +// Simple primitive types (string, integer, number, boolean) without enums +// don't need generated types - they map directly to Go builtins. +// However, nullable primitives DO need generated types (Nullable[T]). +func needsGeneratedType(schema *base.Schema) bool { + if schema == nil { + return false + } + + // Nullable primitives need a generated type (Nullable[T]) + if isNullablePrimitive(schema) { + return true + } + + // Enums always need a generated type + if len(schema.Enum) > 0 { + return true + } + + // Objects need a generated type + if schema.Properties != nil && schema.Properties.Len() > 0 { + return true + } + + // Check explicit type + types := schema.Type + for _, t := range types { + if t == "object" { + return true + } + } + + // Composition types need generated types + if len(schema.AllOf) > 0 || len(schema.AnyOf) > 0 || len(schema.OneOf) > 0 { + return true + } + + // Arrays with complex items need generated types for the array type itself + // But we handle items separately in gatherFromSchema + if schema.Items != nil && schema.Items.A != nil { + itemSchema := schema.Items.A.Schema() + if needsGeneratedType(itemSchema) { + return true + } + } + + // AdditionalProperties with complex schema needs a type + if schema.AdditionalProperties != nil && schema.AdditionalProperties.A != nil { + addSchema := schema.AdditionalProperties.A.Schema() + if needsGeneratedType(addSchema) { + return true + } + } + + // Simple primitives (string, integer, number, boolean) without enum + // don't need generated types + return false +} + +// isNullablePrimitive returns true if the schema is a nullable primitive type. +// Nullable primitives need Nullable[T] wrapper types. +func isNullablePrimitive(schema *base.Schema) bool { + if schema == nil { + return false + } + + // Check for nullable + isNullable := false + // OpenAPI 3.1 style: type array includes "null" + for _, t := range schema.Type { + if t == "null" { + isNullable = true + break + } + } + // OpenAPI 3.0 style: nullable: true + if schema.Nullable != nil && *schema.Nullable { + isNullable = true + } + + if !isNullable { + return false + } + + // Check if it's a primitive type (not object, array, or composition) + if schema.Properties != nil && schema.Properties.Len() > 0 { + return false // object with properties + } + if len(schema.AllOf) > 0 || len(schema.AnyOf) > 0 || len(schema.OneOf) > 0 { + return false // composition type + } + if schema.Items != nil { + return false // array + } + + // Get the primary type + for _, t := range schema.Type { + switch t { + case "string", "integer", "number", "boolean": + return true + case "object": + return false + case "array": + return false + } + } + + return false +} + +func (g *gatherer) gatherFromSchema(schema *base.Schema, basePath SchemaPath, parent *SchemaDescriptor) { + if schema == nil { + return + } + + // Properties + if schema.Properties != nil { + if parent != nil { + parent.Properties = make(map[string]*SchemaDescriptor) + } + for pair := schema.Properties.First(); pair != nil; pair = pair.Next() { + propName := pair.Key() + propProxy := pair.Value() + propPath := basePath.Append("properties", propName) + propDesc := g.gatherFromSchemaProxy(propProxy, propPath, parent) + if parent != nil && propDesc != nil { + parent.Properties[propName] = propDesc + } + } + } + + // Items (array element schema) + if schema.Items != nil && schema.Items.A != nil { + itemsPath := basePath.Append("items") + itemsDesc := g.gatherFromSchemaProxy(schema.Items.A, itemsPath, parent) + if parent != nil && itemsDesc != nil { + parent.Items = itemsDesc + } + } + + // AllOf - inline object members don't need separate types since fields are flattened into parent + // However, inline oneOf/anyOf members DO need union types generated + for i, proxy := range schema.AllOf { + allOfPath := basePath.Append("allOf", fmt.Sprintf("%d", i)) + var allOfDesc *SchemaDescriptor + if proxy.IsReference() { + // References still need to be gathered normally + allOfDesc = g.gatherFromSchemaProxy(proxy, allOfPath, parent) + } else { + memberSchema := proxy.Schema() + // If the allOf member is itself a oneOf/anyOf, we need to generate a union type + if memberSchema != nil && (len(memberSchema.OneOf) > 0 || len(memberSchema.AnyOf) > 0) { + allOfDesc = g.gatherFromSchemaProxy(proxy, allOfPath, parent) + } else { + // Simple inline objects: create descriptor for field extraction but don't generate a type + allOfDesc = g.gatherSchemaDescriptorOnly(proxy, allOfPath, parent) + } + } + if parent != nil && allOfDesc != nil { + parent.AllOf = append(parent.AllOf, allOfDesc) + } + } + + // AnyOf + for i, proxy := range schema.AnyOf { + anyOfPath := basePath.Append("anyOf", fmt.Sprintf("%d", i)) + anyOfDesc := g.gatherFromSchemaProxy(proxy, anyOfPath, parent) + if parent != nil && anyOfDesc != nil { + parent.AnyOf = append(parent.AnyOf, anyOfDesc) + } + } + + // OneOf + for i, proxy := range schema.OneOf { + oneOfPath := basePath.Append("oneOf", fmt.Sprintf("%d", i)) + oneOfDesc := g.gatherFromSchemaProxy(proxy, oneOfPath, parent) + if parent != nil && oneOfDesc != nil { + parent.OneOf = append(parent.OneOf, oneOfDesc) + } + } + + // AdditionalProperties (if it's a schema, not a boolean) + if schema.AdditionalProperties != nil && schema.AdditionalProperties.A != nil { + addPropsPath := basePath.Append("additionalProperties") + addPropsDesc := g.gatherFromSchemaProxy(schema.AdditionalProperties.A, addPropsPath, parent) + if parent != nil && addPropsDesc != nil { + parent.AdditionalProps = addPropsDesc + } + } + + // Not + if schema.Not != nil { + g.gatherFromSchemaProxy(schema.Not, basePath.Append("not"), parent) + } + + // PrefixItems (3.1 tuple validation) + for i, proxy := range schema.PrefixItems { + g.gatherFromSchemaProxy(proxy, basePath.Append("prefixItems", fmt.Sprintf("%d", i)), parent) + } + + // Contains (3.1) + if schema.Contains != nil { + g.gatherFromSchemaProxy(schema.Contains, basePath.Append("contains"), parent) + } + + // If/Then/Else (3.1) + if schema.If != nil { + g.gatherFromSchemaProxy(schema.If, basePath.Append("if"), parent) + } + if schema.Then != nil { + g.gatherFromSchemaProxy(schema.Then, basePath.Append("then"), parent) + } + if schema.Else != nil { + g.gatherFromSchemaProxy(schema.Else, basePath.Append("else"), parent) + } + + // DependentSchemas (3.1) + if schema.DependentSchemas != nil { + for pair := schema.DependentSchemas.First(); pair != nil; pair = pair.Next() { + name := pair.Key() + proxy := pair.Value() + g.gatherFromSchemaProxy(proxy, basePath.Append("dependentSchemas", name), parent) + } + } + + // PatternProperties (3.1) + if schema.PatternProperties != nil { + for pair := schema.PatternProperties.First(); pair != nil; pair = pair.Next() { + pattern := pair.Key() + proxy := pair.Value() + g.gatherFromSchemaProxy(proxy, basePath.Append("patternProperties", pattern), parent) + } + } + + // PropertyNames (3.1) + if schema.PropertyNames != nil { + g.gatherFromSchemaProxy(schema.PropertyNames, basePath.Append("propertyNames"), parent) + } + + // UnevaluatedItems (3.1) + if schema.UnevaluatedItems != nil { + g.gatherFromSchemaProxy(schema.UnevaluatedItems, basePath.Append("unevaluatedItems"), parent) + } + + // UnevaluatedProperties (3.1) - can be schema or bool + if schema.UnevaluatedProperties != nil && schema.UnevaluatedProperties.A != nil { + g.gatherFromSchemaProxy(schema.UnevaluatedProperties.A, basePath.Append("unevaluatedProperties"), parent) + } +} diff --git a/experimental/internal/codegen/gather_operations.go b/experimental/internal/codegen/gather_operations.go new file mode 100644 index 0000000000..0492bbb433 --- /dev/null +++ b/experimental/internal/codegen/gather_operations.go @@ -0,0 +1,864 @@ +package codegen + +import ( + "fmt" + "sort" + "strings" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel/high/base" + v3 "github.com/pb33f/libopenapi/datamodel/high/v3" +) + +// GatherOperations traverses an OpenAPI document and collects all operations. +func GatherOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { + model, err := doc.BuildV3Model() + if err != nil { + return nil, fmt.Errorf("building v3 model: %w", err) + } + if model == nil { + return nil, fmt.Errorf("failed to build v3 model") + } + + g := &operationGatherer{ + paramTracker: paramTracker, + } + + return g.gatherFromDocument(&model.Model) +} + +type operationGatherer struct { + paramTracker *ParamUsageTracker +} + +func (g *operationGatherer) gatherFromDocument(doc *v3.Document) ([]*OperationDescriptor, error) { + var operations []*OperationDescriptor + + if doc.Paths == nil || doc.Paths.PathItems == nil { + return operations, nil + } + + // Collect paths in sorted order for deterministic output + var paths []string + for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { + paths = append(paths, pair.Key()) + } + sort.Strings(paths) + + for _, pathStr := range paths { + pathItem := doc.Paths.PathItems.GetOrZero(pathStr) + if pathItem == nil { + continue + } + + // Gather path-level parameters (shared by all operations on this path) + globalParams, err := g.gatherParameters(pathItem.Parameters) + if err != nil { + return nil, fmt.Errorf("error gathering path-level parameters for %s: %w", pathStr, err) + } + + // Process each operation on this path + ops := pathItem.GetOperations() + if ops == nil { + continue + } + + // Collect methods in sorted order + var methods []string + for pair := ops.First(); pair != nil; pair = pair.Next() { + methods = append(methods, pair.Key()) + } + sort.Strings(methods) + + for _, method := range methods { + op := ops.GetOrZero(method) + if op == nil { + continue + } + + opDesc, err := g.gatherOperation(method, pathStr, op, globalParams) + if err != nil { + return nil, fmt.Errorf("error gathering operation %s %s: %w", method, pathStr, err) + } + operations = append(operations, opDesc) + } + } + + return operations, nil +} + +func (g *operationGatherer) gatherOperation(method, path string, op *v3.Operation, globalParams []*ParameterDescriptor) (*OperationDescriptor, error) { + // Determine operation ID + operationID := op.OperationId + if operationID == "" { + operationID = generateOperationID(method, path) + } + goOperationID := ToGoIdentifier(operationID) + + // Gather operation-level parameters + localParams, err := g.gatherParameters(op.Parameters) + if err != nil { + return nil, fmt.Errorf("error gathering parameters: %w", err) + } + + // Combine global and local parameters (local overrides global) + allParams := combineParameters(globalParams, localParams) + + // Sort path params to match order in path + pathParams := filterParamsByLocation(allParams, "path") + pathParams, err = sortPathParamsByPath(path, pathParams) + if err != nil { + return nil, fmt.Errorf("error sorting path params: %w", err) + } + + // Gather request bodies + bodies, err := g.gatherRequestBodies(operationID, op.RequestBody) + if err != nil { + return nil, fmt.Errorf("error gathering request bodies: %w", err) + } + + // Gather responses + responses, err := g.gatherResponses(operationID, op.Responses) + if err != nil { + return nil, fmt.Errorf("error gathering responses: %w", err) + } + + // Gather security requirements + security := g.gatherSecurity(op.Security) + + queryParams := filterParamsByLocation(allParams, "query") + headerParams := filterParamsByLocation(allParams, "header") + cookieParams := filterParamsByLocation(allParams, "cookie") + + hasParams := len(queryParams)+len(headerParams)+len(cookieParams) > 0 + + desc := &OperationDescriptor{ + OperationID: operationID, + GoOperationID: goOperationID, + Method: strings.ToUpper(method), + Path: path, + Summary: op.Summary, + Description: op.Description, + + PathParams: pathParams, + QueryParams: queryParams, + HeaderParams: headerParams, + CookieParams: cookieParams, + + Bodies: bodies, + Responses: responses, + Security: security, + + HasBody: len(bodies) > 0, + HasParams: hasParams, + ParamsTypeName: goOperationID + "Params", + + Spec: op, + } + + return desc, nil +} + +func (g *operationGatherer) gatherParameters(params []*v3.Parameter) ([]*ParameterDescriptor, error) { + var result []*ParameterDescriptor + + for _, param := range params { + if param == nil { + continue + } + + desc, err := g.gatherParameter(param) + if err != nil { + return nil, fmt.Errorf("error gathering parameter %s: %w", param.Name, err) + } + result = append(result, desc) + } + + return result, nil +} + +func (g *operationGatherer) gatherParameter(param *v3.Parameter) (*ParameterDescriptor, error) { + // Determine style and explode (with defaults based on location) + style := param.Style + if style == "" { + style = DefaultParamStyle(param.In) + } + + explode := DefaultParamExplode(param.In) + if param.Explode != nil { + explode = *param.Explode + } + + // Record param usage for function generation + if g.paramTracker != nil { + g.paramTracker.RecordParam(style, explode) + } + + // Determine encoding mode + isStyled := param.Schema != nil + isJSON := false + isPassThrough := false + + if param.Content != nil && param.Content.Len() > 0 { + // Parameter uses content encoding + isStyled = false + for pair := param.Content.First(); pair != nil; pair = pair.Next() { + contentType := pair.Key() + if IsMediaTypeJSON(contentType) { + isJSON = true + break + } + } + if !isJSON { + isPassThrough = true + } + } + + // Get type declaration from schema + typeDecl := "string" // Default + var schemaDesc *SchemaDescriptor + if param.Schema != nil { + schema := param.Schema.Schema() + if schema != nil { + schemaDesc = &SchemaDescriptor{ + Schema: schema, + } + typeDecl = schemaToGoType(schema) + } + } + + goName := ToCamelCase(param.Name) + + // Handle *bool for Required + required := false + if param.Required != nil { + required = *param.Required + } + + desc := &ParameterDescriptor{ + Name: param.Name, + GoName: goName, + Location: param.In, + Required: required, + + Style: style, + Explode: explode, + + Schema: schemaDesc, + TypeDecl: typeDecl, + + StyleFunc: ComputeStyleFunc(style, explode), + BindFunc: ComputeBindFunc(style, explode), + + IsStyled: isStyled, + IsPassThrough: isPassThrough, + IsJSON: isJSON, + + Spec: param, + } + + return desc, nil +} + +func (g *operationGatherer) gatherRequestBodies(operationID string, bodyRef *v3.RequestBody) ([]*RequestBodyDescriptor, error) { + if bodyRef == nil { + return nil, nil + } + + var bodies []*RequestBodyDescriptor + + if bodyRef.Content == nil { + return bodies, nil + } + + // Collect content types in sorted order + var contentTypes []string + for pair := bodyRef.Content.First(); pair != nil; pair = pair.Next() { + contentTypes = append(contentTypes, pair.Key()) + } + sort.Strings(contentTypes) + + // Determine which is the default (application/json if present) + hasApplicationJSON := false + for _, ct := range contentTypes { + if ct == "application/json" { + hasApplicationJSON = true + break + } + } + + for _, contentType := range contentTypes { + mediaType := bodyRef.Content.GetOrZero(contentType) + if mediaType == nil { + continue + } + + nameTag := ComputeBodyNameTag(contentType) + isDefault := contentType == "application/json" || (!hasApplicationJSON && contentType == contentTypes[0]) + + var schemaDesc *SchemaDescriptor + if mediaType.Schema != nil { + schemaDesc = schemaProxyToDescriptor(mediaType.Schema) + } + + funcSuffix := "" + if !isDefault && nameTag != "" { + funcSuffix = "With" + nameTag + "Body" + } + + goTypeName := operationID + nameTag + "RequestBody" + if nameTag == "" { + goTypeName = operationID + "RequestBody" + } + + // Handle *bool for Required + bodyRequired := false + if bodyRef.Required != nil { + bodyRequired = *bodyRef.Required + } + + desc := &RequestBodyDescriptor{ + ContentType: contentType, + Required: bodyRequired, + Schema: schemaDesc, + + NameTag: nameTag, + GoTypeName: goTypeName, + FuncSuffix: funcSuffix, + IsDefault: isDefault, + IsJSON: IsMediaTypeJSON(contentType), + } + + // Gather encoding options for form data + if mediaType.Encoding != nil && mediaType.Encoding.Len() > 0 { + desc.Encoding = make(map[string]RequestBodyEncoding) + for pair := mediaType.Encoding.First(); pair != nil; pair = pair.Next() { + enc := pair.Value() + desc.Encoding[pair.Key()] = RequestBodyEncoding{ + ContentType: enc.ContentType, + Style: enc.Style, + Explode: enc.Explode, + } + } + } + + bodies = append(bodies, desc) + } + + return bodies, nil +} + +func (g *operationGatherer) gatherResponses(operationID string, responses *v3.Responses) ([]*ResponseDescriptor, error) { + if responses == nil { + return nil, nil + } + + var result []*ResponseDescriptor + + // Gather default response + if responses.Default != nil { + desc, err := g.gatherResponse(operationID, "default", responses.Default) + if err != nil { + return nil, err + } + if desc != nil { + result = append(result, desc) + } + } + + // Gather status code responses + if responses.Codes != nil { + var codes []string + for pair := responses.Codes.First(); pair != nil; pair = pair.Next() { + codes = append(codes, pair.Key()) + } + sort.Strings(codes) + + for _, code := range codes { + respRef := responses.Codes.GetOrZero(code) + if respRef == nil { + continue + } + + desc, err := g.gatherResponse(operationID, code, respRef) + if err != nil { + return nil, err + } + if desc != nil { + result = append(result, desc) + } + } + } + + return result, nil +} + +func (g *operationGatherer) gatherResponse(operationID, statusCode string, resp *v3.Response) (*ResponseDescriptor, error) { + if resp == nil { + return nil, nil + } + + var contents []*ResponseContentDescriptor + if resp.Content != nil { + var contentTypes []string + for pair := resp.Content.First(); pair != nil; pair = pair.Next() { + contentTypes = append(contentTypes, pair.Key()) + } + sort.Strings(contentTypes) + + for _, contentType := range contentTypes { + mediaType := resp.Content.GetOrZero(contentType) + if mediaType == nil { + continue + } + + var schemaDesc *SchemaDescriptor + if mediaType.Schema != nil { + schemaDesc = schemaProxyToDescriptor(mediaType.Schema) + } + + nameTag := ComputeBodyNameTag(contentType) + + contents = append(contents, &ResponseContentDescriptor{ + ContentType: contentType, + Schema: schemaDesc, + NameTag: nameTag, + IsJSON: IsMediaTypeJSON(contentType), + }) + } + } + + var headers []*ResponseHeaderDescriptor + if resp.Headers != nil { + var headerNames []string + for pair := resp.Headers.First(); pair != nil; pair = pair.Next() { + headerNames = append(headerNames, pair.Key()) + } + sort.Strings(headerNames) + + for _, name := range headerNames { + header := resp.Headers.GetOrZero(name) + if header == nil { + continue + } + + var schemaDesc *SchemaDescriptor + if header.Schema != nil { + schemaDesc = schemaProxyToDescriptor(header.Schema) + } + + headers = append(headers, &ResponseHeaderDescriptor{ + Name: name, + GoName: ToCamelCase(name), + Required: header.Required, + Schema: schemaDesc, + }) + } + } + + description := "" + if resp.Description != "" { + description = resp.Description + } + + return &ResponseDescriptor{ + StatusCode: statusCode, + Description: description, + Contents: contents, + Headers: headers, + }, nil +} + +func (g *operationGatherer) gatherSecurity(security []*base.SecurityRequirement) []SecurityRequirement { + if security == nil { + return nil + } + + var result []SecurityRequirement + for _, req := range security { + if req == nil || req.Requirements == nil { + continue + } + for pair := req.Requirements.First(); pair != nil; pair = pair.Next() { + result = append(result, SecurityRequirement{ + Name: pair.Key(), + Scopes: pair.Value(), + }) + } + } + return result +} + +// Helper functions + +func generateOperationID(method, path string) string { + // Generate operation ID from method and path + // GET /users/{id} -> GetUsersId + id := strings.ToLower(method) + for _, part := range strings.Split(path, "/") { + if part == "" { + continue + } + // Remove path parameter braces + part = strings.TrimPrefix(part, "{") + part = strings.TrimSuffix(part, "}") + id += "-" + part + } + return ToCamelCase(id) +} + +func combineParameters(global, local []*ParameterDescriptor) []*ParameterDescriptor { + // Local parameters override global parameters with the same name and location + seen := make(map[string]bool) + var result []*ParameterDescriptor + + for _, p := range local { + key := p.Location + ":" + p.Name + seen[key] = true + result = append(result, p) + } + + for _, p := range global { + key := p.Location + ":" + p.Name + if !seen[key] { + result = append(result, p) + } + } + + return result +} + +func filterParamsByLocation(params []*ParameterDescriptor, location string) []*ParameterDescriptor { + var result []*ParameterDescriptor + for _, p := range params { + if p.Location == location { + result = append(result, p) + } + } + return result +} + +func sortPathParamsByPath(path string, params []*ParameterDescriptor) ([]*ParameterDescriptor, error) { + // Extract parameter names from path in order + var pathParamNames []string + parts := strings.Split(path, "/") + for _, part := range parts { + if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") { + name := strings.TrimPrefix(part, "{") + name = strings.TrimSuffix(name, "}") + pathParamNames = append(pathParamNames, name) + } + } + + // Build a map of params by name + paramMap := make(map[string]*ParameterDescriptor) + for _, p := range params { + paramMap[p.Name] = p + } + + // Sort params according to path order + var result []*ParameterDescriptor + for _, name := range pathParamNames { + if p, ok := paramMap[name]; ok { + result = append(result, p) + } + } + + return result, nil +} + +// GatherWebhookOperations traverses an OpenAPI document and collects operations from webhooks. +func GatherWebhookOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { + model, err := doc.BuildV3Model() + if err != nil { + return nil, fmt.Errorf("building v3 model: %w", err) + } + if model == nil { + return nil, fmt.Errorf("failed to build v3 model") + } + + g := &operationGatherer{ + paramTracker: paramTracker, + } + + return g.gatherWebhooks(&model.Model) +} + +// GatherCallbackOperations traverses an OpenAPI document and collects operations from callbacks. +func GatherCallbackOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { + model, err := doc.BuildV3Model() + if err != nil { + return nil, fmt.Errorf("building v3 model: %w", err) + } + if model == nil { + return nil, fmt.Errorf("failed to build v3 model") + } + + g := &operationGatherer{ + paramTracker: paramTracker, + } + + return g.gatherCallbacks(&model.Model) +} + +func (g *operationGatherer) gatherWebhooks(doc *v3.Document) ([]*OperationDescriptor, error) { + var operations []*OperationDescriptor + + if doc.Webhooks == nil || doc.Webhooks.Len() == 0 { + return operations, nil + } + + // Collect webhook names in sorted order for deterministic output + var webhookNames []string + for pair := doc.Webhooks.First(); pair != nil; pair = pair.Next() { + webhookNames = append(webhookNames, pair.Key()) + } + sort.Strings(webhookNames) + + for _, webhookName := range webhookNames { + pathItem := doc.Webhooks.GetOrZero(webhookName) + if pathItem == nil { + continue + } + + // Gather path-level parameters + globalParams, err := g.gatherParameters(pathItem.Parameters) + if err != nil { + return nil, fmt.Errorf("error gathering parameters for webhook %s: %w", webhookName, err) + } + + ops := pathItem.GetOperations() + if ops == nil { + continue + } + + var methods []string + for pair := ops.First(); pair != nil; pair = pair.Next() { + methods = append(methods, pair.Key()) + } + sort.Strings(methods) + + for _, method := range methods { + op := ops.GetOrZero(method) + if op == nil { + continue + } + + // For webhooks, Path is empty (no URL path in the spec) + opDesc, err := g.gatherOperation(method, "", op, globalParams) + if err != nil { + return nil, fmt.Errorf("error gathering webhook operation %s %s: %w", method, webhookName, err) + } + + // Override operation ID if not set - use webhook name + method + if op.OperationId == "" { + opDesc.OperationID = ToCamelCase(method + "-" + webhookName) + opDesc.GoOperationID = ToGoIdentifier(opDesc.OperationID) + opDesc.ParamsTypeName = opDesc.GoOperationID + "Params" + } + + opDesc.Source = OperationSourceWebhook + opDesc.WebhookName = webhookName + + operations = append(operations, opDesc) + } + } + + return operations, nil +} + +func (g *operationGatherer) gatherCallbacks(doc *v3.Document) ([]*OperationDescriptor, error) { + var operations []*OperationDescriptor + + if doc.Paths == nil || doc.Paths.PathItems == nil { + return operations, nil + } + + // Iterate all paths in sorted order + var paths []string + for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { + paths = append(paths, pair.Key()) + } + sort.Strings(paths) + + for _, pathStr := range paths { + pathItem := doc.Paths.PathItems.GetOrZero(pathStr) + if pathItem == nil { + continue + } + + pathOps := pathItem.GetOperations() + if pathOps == nil { + continue + } + + var methods []string + for pair := pathOps.First(); pair != nil; pair = pair.Next() { + methods = append(methods, pair.Key()) + } + sort.Strings(methods) + + for _, method := range methods { + parentOp := pathOps.GetOrZero(method) + if parentOp == nil || parentOp.Callbacks == nil || parentOp.Callbacks.Len() == 0 { + continue + } + + parentOpID := parentOp.OperationId + if parentOpID == "" { + parentOpID = generateOperationID(method, pathStr) + } + + // Collect callback names in sorted order + var callbackNames []string + for pair := parentOp.Callbacks.First(); pair != nil; pair = pair.Next() { + callbackNames = append(callbackNames, pair.Key()) + } + sort.Strings(callbackNames) + + for _, callbackName := range callbackNames { + callback := parentOp.Callbacks.GetOrZero(callbackName) + if callback == nil || callback.Expression == nil || callback.Expression.Len() == 0 { + continue + } + + // Iterate callback expressions in sorted order + var expressions []string + for pair := callback.Expression.First(); pair != nil; pair = pair.Next() { + expressions = append(expressions, pair.Key()) + } + sort.Strings(expressions) + + for _, expression := range expressions { + cbPathItem := callback.Expression.GetOrZero(expression) + if cbPathItem == nil { + continue + } + + cbOps := cbPathItem.GetOperations() + if cbOps == nil { + continue + } + + var cbMethods []string + for pair := cbOps.First(); pair != nil; pair = pair.Next() { + cbMethods = append(cbMethods, pair.Key()) + } + sort.Strings(cbMethods) + + for _, cbMethod := range cbMethods { + cbOp := cbOps.GetOrZero(cbMethod) + if cbOp == nil { + continue + } + + // URL expression is stored as path but params are not extracted + // (expressions are runtime-evaluated) + opDesc, err := g.gatherOperation(cbMethod, expression, cbOp, nil) + if err != nil { + return nil, fmt.Errorf("error gathering callback operation %s %s %s: %w", cbMethod, callbackName, expression, err) + } + + // Override operation ID if not set + if cbOp.OperationId == "" { + opDesc.OperationID = ToCamelCase(parentOpID + "-" + callbackName) + opDesc.GoOperationID = ToGoIdentifier(opDesc.OperationID) + opDesc.ParamsTypeName = opDesc.GoOperationID + "Params" + } + + // Clear path params since callback URLs are runtime expressions + opDesc.PathParams = nil + + opDesc.Source = OperationSourceCallback + opDesc.CallbackName = callbackName + opDesc.ParentOpID = parentOpID + + operations = append(operations, opDesc) + } + } + } + } + } + + return operations, nil +} + +// schemaProxyToDescriptor converts a schema proxy to a basic descriptor. +// This is a simplified version - for full type resolution, use the schema gatherer. +func schemaProxyToDescriptor(proxy *base.SchemaProxy) *SchemaDescriptor { + if proxy == nil { + return nil + } + + schema := proxy.Schema() + if schema == nil { + return nil + } + + desc := &SchemaDescriptor{ + Schema: schema, + } + + // Capture reference if this is a reference schema + if proxy.IsReference() { + desc.Ref = proxy.GetReference() + } + + return desc +} + +// schemaToGoType converts a schema to a Go type string. +// This is a simplified version for parameter types. +func schemaToGoType(schema *base.Schema) string { + if schema == nil { + return "interface{}" + } + + // Check for array + if schema.Items != nil && schema.Items.A != nil { + itemType := "interface{}" + if itemSchema := schema.Items.A.Schema(); itemSchema != nil { + itemType = schemaToGoType(itemSchema) + } + return "[]" + itemType + } + + // Check explicit type + for _, t := range schema.Type { + switch t { + case "string": + if schema.Format == "date-time" { + return "time.Time" + } + if schema.Format == "date" { + return "Date" + } + if schema.Format == "uuid" { + return "uuid.UUID" + } + return "string" + case "integer": + if schema.Format == "int64" { + return "int64" + } + if schema.Format == "int32" { + return "int32" + } + return "int" + case "number": + if schema.Format == "float" { + return "float32" + } + return "float64" + case "boolean": + return "bool" + case "array": + // Handled above + return "[]interface{}" + case "object": + return "map[string]interface{}" + } + } + + return "interface{}" +} diff --git a/experimental/internal/codegen/identifiers.go b/experimental/internal/codegen/identifiers.go new file mode 100644 index 0000000000..6a8f58f05b --- /dev/null +++ b/experimental/internal/codegen/identifiers.go @@ -0,0 +1,125 @@ +package codegen + +import ( + "strings" + "unicode" +) + +// Go keywords that can't be used as identifiers +var goKeywords = map[string]bool{ + "break": true, + "case": true, + "chan": true, + "const": true, + "continue": true, + "default": true, + "defer": true, + "else": true, + "fallthrough": true, + "for": true, + "func": true, + "go": true, + "goto": true, + "if": true, + "import": true, + "interface": true, + "map": true, + "package": true, + "range": true, + "return": true, + "select": true, + "struct": true, + "switch": true, + "type": true, + "var": true, +} + +// IsGoKeyword returns true if s is a Go keyword. +func IsGoKeyword(s string) bool { + return goKeywords[s] +} + +// ToCamelCase converts a string to CamelCase (PascalCase). +// It treats hyphens, underscores, spaces, and other non-alphanumeric characters as word separators. +// Example: "user-name" -> "UserName", "user_id" -> "UserId" +func ToCamelCase(s string) string { + if s == "" { + return "" + } + + var result strings.Builder + capitalizeNext := true + + for _, r := range s { + if isWordSeparator(r) { + capitalizeNext = true + continue + } + + if !unicode.IsLetter(r) && !unicode.IsDigit(r) { + capitalizeNext = true + continue + } + + if capitalizeNext { + result.WriteRune(unicode.ToUpper(r)) + capitalizeNext = false + } else { + result.WriteRune(r) + } + } + + return result.String() +} + +// LowercaseFirstCharacter lowercases only the first character of a string. +// Example: "UserName" -> "userName" +func LowercaseFirstCharacter(s string) string { + if s == "" { + return "" + } + runes := []rune(s) + runes[0] = unicode.ToLower(runes[0]) + return string(runes) +} + +// UppercaseFirstCharacter uppercases only the first character of a string. +// Example: "userName" -> "UserName" +func UppercaseFirstCharacter(s string) string { + if s == "" { + return "" + } + runes := []rune(s) + runes[0] = unicode.ToUpper(runes[0]) + return string(runes) +} + +// isWordSeparator returns true if the rune is a word separator. +func isWordSeparator(r rune) bool { + return r == '-' || r == '_' || r == ' ' || r == '.' || r == '/' +} + +// ToGoIdentifier converts a string to a valid Go identifier. +// It converts to CamelCase, handles leading digits, and avoids Go keywords. +func ToGoIdentifier(s string) string { + result := ToCamelCase(s) + + // Handle empty result + if result == "" { + return "Empty" + } + + // Handle leading digits + if result[0] >= '0' && result[0] <= '9' { + result = "N" + result + } + + // Handle Go keywords - check both the original input and lowercase result + // "type" -> "Type" but we still want to avoid "Type" being used as-is + // since user might write it as lowercase in code + if IsGoKeyword(s) || IsGoKeyword(strings.ToLower(result)) { + result = result + "_" + } + + return result +} diff --git a/experimental/internal/codegen/identifiers_test.go b/experimental/internal/codegen/identifiers_test.go new file mode 100644 index 0000000000..4d5eca6328 --- /dev/null +++ b/experimental/internal/codegen/identifiers_test.go @@ -0,0 +1,129 @@ +package codegen + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsGoKeyword(t *testing.T) { + keywords := []string{ + "break", "case", "chan", "const", "continue", + "default", "defer", "else", "fallthrough", "for", + "func", "go", "goto", "if", "import", + "interface", "map", "package", "range", "return", + "select", "struct", "switch", "type", "var", + } + + for _, kw := range keywords { + t.Run(kw, func(t *testing.T) { + assert.True(t, IsGoKeyword(kw), "%s should be a keyword", kw) + }) + } + + nonKeywords := []string{ + "user", "name", "id", "Type", "Interface", "Map", + "string", "int", "bool", "error", // predeclared but not keywords + } + + for _, nkw := range nonKeywords { + t.Run(nkw+"_not_keyword", func(t *testing.T) { + assert.False(t, IsGoKeyword(nkw), "%s should not be a keyword", nkw) + }) + } +} + +func TestToCamelCase(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"", ""}, + {"user", "User"}, + {"user_name", "UserName"}, + {"user-name", "UserName"}, + {"user.name", "UserName"}, + {"user name", "UserName"}, + {"USER", "USER"}, + {"USER_NAME", "USERNAME"}, + {"123", "123"}, + {"user123", "User123"}, + {"user123name", "User123name"}, + {"get-users-by-id", "GetUsersById"}, + {"__private", "Private"}, + {"a_b_c", "ABC"}, + {"already_CamelCase", "AlreadyCamelCase"}, + {"path/to/resource", "PathToResource"}, + } + + for _, tc := range tests { + t.Run(tc.input, func(t *testing.T) { + result := ToCamelCase(tc.input) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestLowercaseFirstCharacter(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"", ""}, + {"User", "user"}, + {"UserName", "userName"}, + {"user", "user"}, + {"ABC", "aBC"}, + {"123", "123"}, + } + + for _, tc := range tests { + t.Run(tc.input, func(t *testing.T) { + result := LowercaseFirstCharacter(tc.input) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestUppercaseFirstCharacter(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"", ""}, + {"user", "User"}, + {"userName", "UserName"}, + {"User", "User"}, + {"abc", "Abc"}, + } + + for _, tc := range tests { + t.Run(tc.input, func(t *testing.T) { + result := UppercaseFirstCharacter(tc.input) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestToGoIdentifier(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"user", "User"}, + {"user_name", "UserName"}, + {"123abc", "N123abc"}, + {"type", "Type_"}, + {"map", "Map_"}, + {"interface", "Interface_"}, + {"", "Empty"}, + {"get-users", "GetUsers"}, + } + + for _, tc := range tests { + t.Run(tc.input, func(t *testing.T) { + result := ToGoIdentifier(tc.input) + assert.Equal(t, tc.expected, result) + }) + } +} diff --git a/experimental/internal/codegen/initiatorgen.go b/experimental/internal/codegen/initiatorgen.go new file mode 100644 index 0000000000..67a9aa08fa --- /dev/null +++ b/experimental/internal/codegen/initiatorgen.go @@ -0,0 +1,216 @@ +package codegen + +import ( + "bytes" + "fmt" + "strings" + "text/template" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// InitiatorTemplateData is passed to initiator templates. +type InitiatorTemplateData struct { + Prefix string // "Webhook" or "Callback" + PrefixLower string // "webhook" or "callback" + Operations []*OperationDescriptor // Operations to generate for +} + +// InitiatorGenerator generates initiator (sender) code from operation descriptors. +// It is parameterized by prefix to support both webhooks and callbacks. +type InitiatorGenerator struct { + tmpl *template.Template + prefix string // "Webhook" or "Callback" + schemaIndex map[string]*SchemaDescriptor + generateSimple bool + modelsPackage *ModelsPackage +} + +// NewInitiatorGenerator creates a new initiator generator. +func NewInitiatorGenerator(prefix string, schemaIndex map[string]*SchemaDescriptor, generateSimple bool, modelsPackage *ModelsPackage) (*InitiatorGenerator, error) { + tmpl := template.New("initiator").Funcs(templates.Funcs()).Funcs(clientFuncs(schemaIndex, modelsPackage)) + + // Parse initiator templates + for _, pt := range templates.InitiatorTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + pt.Template) + if err != nil { + return nil, fmt.Errorf("failed to read initiator template %s: %w", pt.Template, err) + } + _, err = tmpl.New(pt.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse initiator template %s: %w", pt.Template, err) + } + } + + // Parse shared templates (param_types) + for _, st := range templates.SharedServerTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + st.Template) + if err != nil { + return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) + } + _, err = tmpl.New(st.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) + } + } + + return &InitiatorGenerator{ + tmpl: tmpl, + prefix: prefix, + schemaIndex: schemaIndex, + generateSimple: generateSimple, + modelsPackage: modelsPackage, + }, nil +} + +func (g *InitiatorGenerator) templateData(ops []*OperationDescriptor) InitiatorTemplateData { + return InitiatorTemplateData{ + Prefix: g.prefix, + PrefixLower: strings.ToLower(g.prefix), + Operations: ops, + } +} + +// GenerateBase generates the base initiator types and helpers. +func (g *InitiatorGenerator) GenerateBase(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "initiator_base", g.templateData(ops)); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateInterface generates the InitiatorInterface. +func (g *InitiatorGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "initiator_interface", g.templateData(ops)); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateMethods generates the Initiator methods. +func (g *InitiatorGenerator) GenerateMethods(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "initiator_methods", g.templateData(ops)); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateRequestBuilders generates the request builder functions. +func (g *InitiatorGenerator) GenerateRequestBuilders(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "initiator_request_builders", g.templateData(ops)); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateSimple generates the SimpleInitiator with typed responses. +func (g *InitiatorGenerator) GenerateSimple(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "initiator_simple", g.templateData(ops)); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateParamTypes generates the parameter struct types. +func (g *InitiatorGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateRequestBodyTypes generates type aliases for request bodies. +func (g *InitiatorGenerator) GenerateRequestBodyTypes(ops []*OperationDescriptor) string { + var buf bytes.Buffer + pkgPrefix := g.modelsPackage.Prefix() + + for _, op := range ops { + for _, body := range op.Bodies { + if !body.IsJSON { + continue + } + var targetType string + if body.Schema != nil { + if body.Schema.Ref != "" { + if target, ok := g.schemaIndex[body.Schema.Ref]; ok { + targetType = pkgPrefix + target.ShortName + } + } else if body.Schema.ShortName != "" { + targetType = pkgPrefix + body.Schema.ShortName + } + } + if targetType == "" { + targetType = "interface{}" + } + buf.WriteString(fmt.Sprintf("type %s = %s\n\n", body.GoTypeName, targetType)) + } + } + + return buf.String() +} + +// GenerateInitiator generates the complete initiator code. +func (g *InitiatorGenerator) GenerateInitiator(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + + // Generate request body type aliases first + bodyTypes := g.GenerateRequestBodyTypes(ops) + buf.WriteString(bodyTypes) + + // Generate base initiator + base, err := g.GenerateBase(ops) + if err != nil { + return "", fmt.Errorf("generating base initiator: %w", err) + } + buf.WriteString(base) + buf.WriteString("\n") + + // Generate interface + iface, err := g.GenerateInterface(ops) + if err != nil { + return "", fmt.Errorf("generating initiator interface: %w", err) + } + buf.WriteString(iface) + buf.WriteString("\n") + + // Generate param types + paramTypes, err := g.GenerateParamTypes(ops) + if err != nil { + return "", fmt.Errorf("generating param types: %w", err) + } + buf.WriteString(paramTypes) + buf.WriteString("\n") + + // Generate methods + methods, err := g.GenerateMethods(ops) + if err != nil { + return "", fmt.Errorf("generating initiator methods: %w", err) + } + buf.WriteString(methods) + buf.WriteString("\n") + + // Generate request builders + builders, err := g.GenerateRequestBuilders(ops) + if err != nil { + return "", fmt.Errorf("generating request builders: %w", err) + } + buf.WriteString(builders) + buf.WriteString("\n") + + // Generate simple initiator if requested + if g.generateSimple { + simple, err := g.GenerateSimple(ops) + if err != nil { + return "", fmt.Errorf("generating simple initiator: %w", err) + } + buf.WriteString(simple) + } + + return buf.String(), nil +} diff --git a/experimental/internal/codegen/inline.go b/experimental/internal/codegen/inline.go new file mode 100644 index 0000000000..25767cffa8 --- /dev/null +++ b/experimental/internal/codegen/inline.go @@ -0,0 +1,92 @@ +package codegen + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" +) + +// generateEmbeddedSpec produces Go code that embeds the raw OpenAPI spec as +// gzip+base64 encoded data, with a public GetSwaggerSpecJSON() function to +// retrieve the decompressed JSON bytes. +func generateEmbeddedSpec(specData []byte) (string, error) { + // Gzip compress + var buf bytes.Buffer + gz, err := gzip.NewWriterLevel(&buf, gzip.BestCompression) + if err != nil { + return "", fmt.Errorf("creating gzip writer: %w", err) + } + if _, err := gz.Write(specData); err != nil { + return "", fmt.Errorf("gzip writing: %w", err) + } + if err := gz.Close(); err != nil { + return "", fmt.Errorf("gzip close: %w", err) + } + + // Base64 encode + encoded := base64.StdEncoding.EncodeToString(buf.Bytes()) + + // Split into 80-char chunks + var chunks []string + for len(encoded) > 0 { + end := 80 + if end > len(encoded) { + end = len(encoded) + } + chunks = append(chunks, encoded[:end]) + encoded = encoded[end:] + } + + // Build Go code + var b strings.Builder + + b.WriteString("// Base64-encoded, gzip-compressed OpenAPI spec.\n") + b.WriteString("var swaggerSpecJSON = []string{\n") + for _, chunk := range chunks { + fmt.Fprintf(&b, "\t%q,\n", chunk) + } + b.WriteString("}\n\n") + + b.WriteString("// decodeSwaggerSpec decodes and decompresses the embedded spec.\n") + b.WriteString("func decodeSwaggerSpec() ([]byte, error) {\n") + b.WriteString("\tjoined := strings.Join(swaggerSpecJSON, \"\")\n") + b.WriteString("\traw, err := base64.StdEncoding.DecodeString(joined)\n") + b.WriteString("\tif err != nil {\n") + b.WriteString("\t\treturn nil, fmt.Errorf(\"decoding base64: %w\", err)\n") + b.WriteString("\t}\n") + b.WriteString("\tr, err := gzip.NewReader(bytes.NewReader(raw))\n") + b.WriteString("\tif err != nil {\n") + b.WriteString("\t\treturn nil, fmt.Errorf(\"creating gzip reader: %w\", err)\n") + b.WriteString("\t}\n") + b.WriteString("\tdefer r.Close()\n") + b.WriteString("\tvar out bytes.Buffer\n") + b.WriteString("\tif _, err := out.ReadFrom(r); err != nil {\n") + b.WriteString("\t\treturn nil, fmt.Errorf(\"decompressing: %w\", err)\n") + b.WriteString("\t}\n") + b.WriteString("\treturn out.Bytes(), nil\n") + b.WriteString("}\n\n") + + b.WriteString("// decodeSwaggerSpecCached returns a closure that caches the decoded spec.\n") + b.WriteString("func decodeSwaggerSpecCached() func() ([]byte, error) {\n") + b.WriteString("\tvar cached []byte\n") + b.WriteString("\tvar cachedErr error\n") + b.WriteString("\tvar once sync.Once\n") + b.WriteString("\treturn func() ([]byte, error) {\n") + b.WriteString("\t\tonce.Do(func() {\n") + b.WriteString("\t\t\tcached, cachedErr = decodeSwaggerSpec()\n") + b.WriteString("\t\t})\n") + b.WriteString("\t\treturn cached, cachedErr\n") + b.WriteString("\t}\n") + b.WriteString("}\n\n") + + b.WriteString("var swaggerSpec = decodeSwaggerSpecCached()\n\n") + + b.WriteString("// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes.\n") + b.WriteString("func GetSwaggerSpecJSON() ([]byte, error) {\n") + b.WriteString("\treturn swaggerSpec()\n") + b.WriteString("}\n") + + return b.String(), nil +} diff --git a/experimental/internal/codegen/inline_test.go b/experimental/internal/codegen/inline_test.go new file mode 100644 index 0000000000..ae35938493 --- /dev/null +++ b/experimental/internal/codegen/inline_test.go @@ -0,0 +1,139 @@ +package codegen + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "strings" + "testing" + + "github.com/pb33f/libopenapi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGenerateEmbeddedSpec(t *testing.T) { + specData := []byte(`{"openapi":"3.0.0","info":{"title":"Test","version":"1.0"}}`) + + code, err := generateEmbeddedSpec(specData) + require.NoError(t, err) + + // Should contain the chunked base64 variable + assert.Contains(t, code, "var swaggerSpecJSON = []string{") + + // Should contain the decode function + assert.Contains(t, code, "func decodeSwaggerSpec() ([]byte, error)") + + // Should contain the cached decode function + assert.Contains(t, code, "func decodeSwaggerSpecCached() func() ([]byte, error)") + + // Should contain the public API + assert.Contains(t, code, "func GetSwaggerSpecJSON() ([]byte, error)") + + // Should contain the cached var + assert.Contains(t, code, "var swaggerSpec = decodeSwaggerSpecCached()") +} + +func TestGenerateEmbeddedSpecRoundTrip(t *testing.T) { + specData := []byte(`{"openapi":"3.0.0","info":{"title":"Test API","version":"1.0"},"paths":{}}`) + + code, err := generateEmbeddedSpec(specData) + require.NoError(t, err) + + // Extract the base64 chunks from the generated code + var chunks []string + for _, line := range strings.Split(code, "\n") { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, `"`) && strings.HasSuffix(line, `",`) { + // Remove quotes and trailing comma + chunk := line[1 : len(line)-2] + chunks = append(chunks, chunk) + } + } + require.NotEmpty(t, chunks, "should have extracted base64 chunks") + + // Decode base64 + joined := strings.Join(chunks, "") + raw, err := base64.StdEncoding.DecodeString(joined) + require.NoError(t, err) + + // Decompress gzip + r, err := gzip.NewReader(bytes.NewReader(raw)) + require.NoError(t, err) + defer func() { _ = r.Close() }() + + var out bytes.Buffer + _, err = out.ReadFrom(r) + require.NoError(t, err) + + // Should match original spec + assert.Equal(t, specData, out.Bytes()) +} + +func TestGenerateEmbeddedSpecInGenerate(t *testing.T) { + spec := `openapi: "3.0.0" +info: + title: Test API + version: "1.0" +paths: {} +components: + schemas: + Pet: + type: object + properties: + name: + type: string +` + + specBytes := []byte(spec) + + doc, err := libopenapi.NewDocument(specBytes) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + } + + code, err := Generate(doc, specBytes, cfg) + require.NoError(t, err) + + // Should contain the model type + assert.Contains(t, code, "type Pet struct") + + // Should contain the embedded spec + assert.Contains(t, code, "GetSwaggerSpecJSON") + assert.Contains(t, code, "swaggerSpecJSON") +} + +func TestGenerateWithNilSpecData(t *testing.T) { + spec := `openapi: "3.0.0" +info: + title: Test API + version: "1.0" +paths: {} +components: + schemas: + Pet: + type: object + properties: + name: + type: string +` + + doc, err := libopenapi.NewDocument([]byte(spec)) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + } + + code, err := Generate(doc, nil, cfg) + require.NoError(t, err) + + // Should contain the model type + assert.Contains(t, code, "type Pet struct") + + // Should NOT contain the embedded spec + assert.NotContains(t, code, "GetSwaggerSpecJSON") + assert.NotContains(t, code, "swaggerSpecJSON") +} diff --git a/experimental/internal/codegen/namemangling.go b/experimental/internal/codegen/namemangling.go new file mode 100644 index 0000000000..9dff27a642 --- /dev/null +++ b/experimental/internal/codegen/namemangling.go @@ -0,0 +1,420 @@ +package codegen + +import ( + "strings" + "unicode" +) + +// NameMangling configures how OpenAPI names are converted to valid Go identifiers. +type NameMangling struct { + // CharacterSubstitutions maps characters to their word replacements. + // Used when these characters appear at the start of a name. + // Example: '$' -> "DollarSign", '-' -> "Minus" + CharacterSubstitutions map[string]string `yaml:"character-substitutions,omitempty"` + + // WordSeparators is a string of characters that mark word boundaries. + // When encountered, the next letter is capitalized. + // Example: "-_. " means "foo-bar" becomes "FooBar" + WordSeparators string `yaml:"word-separators,omitempty"` + + // NumericPrefix is prepended when a name starts with a digit. + // Example: "N" means "123foo" becomes "N123foo" + NumericPrefix string `yaml:"numeric-prefix,omitempty"` + + // KeywordPrefix is prepended when a name conflicts with a Go keyword. + // Example: "_" means "type" becomes "_type" + KeywordPrefix string `yaml:"keyword-prefix,omitempty"` + + // Initialisms is a list of words that should be all-uppercase. + // Example: ["ID", "HTTP", "URL"] means "userId" becomes "UserID" + Initialisms []string `yaml:"initialisms,omitempty"` +} + +// DefaultNameMangling returns sensible defaults for name mangling. +func DefaultNameMangling() NameMangling { + return NameMangling{ + CharacterSubstitutions: map[string]string{ + "$": "DollarSign", + "-": "Minus", + "+": "Plus", + "&": "And", + "|": "Or", + "~": "Tilde", + "=": "Equal", + ">": "GreaterThan", + "<": "LessThan", + "#": "Hash", + ".": "Dot", + "*": "Asterisk", + "^": "Caret", + "%": "Percent", + "_": "Underscore", + "@": "At", + "!": "Bang", + "?": "Question", + "/": "Slash", + "\\": "Backslash", + ":": "Colon", + ";": "Semicolon", + "'": "Apos", + "\"": "Quote", + "`": "Backtick", + "(": "LParen", + ")": "RParen", + "[": "LBracket", + "]": "RBracket", + "{": "LBrace", + "}": "RBrace", + }, + WordSeparators: "-#@!$&=.+:;_~ (){}[]|<>?/\\", + NumericPrefix: "N", + KeywordPrefix: "_", + Initialisms: []string{ + "ACL", "API", "ASCII", "CPU", "CSS", "DB", "DNS", "EOF", + "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", + "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", + "TLS", "TTL", "UDP", "UI", "UID", "GID", "URI", "URL", + "UTF8", "UUID", "VM", "XML", "XMPP", "XSRF", "XSS", + "SIP", "RTP", "AMQP", "TS", + }, + } +} + +// Merge returns a new NameMangling with user values overlaid on defaults. +// Non-zero user values override defaults. +func (n NameMangling) Merge(user NameMangling) NameMangling { + result := n + + // Merge character substitutions (user overrides/adds to defaults) + if len(user.CharacterSubstitutions) > 0 { + merged := make(map[string]string, len(n.CharacterSubstitutions)) + for k, v := range n.CharacterSubstitutions { + merged[k] = v + } + for k, v := range user.CharacterSubstitutions { + if v == "" { + // Empty string means "remove this substitution" + delete(merged, k) + } else { + merged[k] = v + } + } + result.CharacterSubstitutions = merged + } + + if user.WordSeparators != "" { + result.WordSeparators = user.WordSeparators + } + if user.NumericPrefix != "" { + result.NumericPrefix = user.NumericPrefix + } + if user.KeywordPrefix != "" { + result.KeywordPrefix = user.KeywordPrefix + } + if len(user.Initialisms) > 0 { + result.Initialisms = user.Initialisms + } + + return result +} + +// NameSubstitutions holds direct name overrides for generated identifiers. +type NameSubstitutions struct { + // TypeNames maps generated type names to user-preferred names. + // Example: {"MyGeneratedType": "MyPreferredName"} + TypeNames map[string]string `yaml:"type-names,omitempty"` + + // PropertyNames maps generated property/field names to user-preferred names. + // Example: {"GeneratedField": "PreferredField"} + PropertyNames map[string]string `yaml:"property-names,omitempty"` +} + +// NameConverter handles converting OpenAPI names to Go identifiers. +type NameConverter struct { + mangling NameMangling + substitutions NameSubstitutions + initialismSet map[string]bool +} + +// NewNameConverter creates a NameConverter with the given configuration. +func NewNameConverter(mangling NameMangling, substitutions NameSubstitutions) *NameConverter { + initialismSet := make(map[string]bool, len(mangling.Initialisms)) + for _, init := range mangling.Initialisms { + initialismSet[strings.ToUpper(init)] = true + } + return &NameConverter{ + mangling: mangling, + substitutions: substitutions, + initialismSet: initialismSet, + } +} + +// ToTypeName converts an OpenAPI schema name to a Go type name. +func (c *NameConverter) ToTypeName(name string) string { + // Check for direct substitution first + if sub, ok := c.substitutions.TypeNames[name]; ok { + return sub + } + return c.toGoIdentifier(name, true) +} + +// ToTypeNamePart converts a name to a type name component that will be joined with others. +// Unlike ToTypeName, it doesn't add a numeric prefix since the result won't be the start of an identifier. +func (c *NameConverter) ToTypeNamePart(name string) string { + // Check for direct substitution first + if sub, ok := c.substitutions.TypeNames[name]; ok { + return sub + } + return c.toGoIdentifierPart(name) +} + +// ToPropertyName converts an OpenAPI property name to a Go field name. +func (c *NameConverter) ToPropertyName(name string) string { + // Check for direct substitution first + if sub, ok := c.substitutions.PropertyNames[name]; ok { + return sub + } + return c.toGoIdentifier(name, true) +} + +// ToVariableName converts an OpenAPI name to a Go variable name (unexported). +func (c *NameConverter) ToVariableName(name string) string { + id := c.toGoIdentifier(name, false) + if id == "" { + return id + } + // Make first letter lowercase + runes := []rune(id) + runes[0] = unicode.ToLower(runes[0]) + return string(runes) +} + +// toGoIdentifier converts a name to a valid Go identifier. +func (c *NameConverter) toGoIdentifier(name string, exported bool) string { + if name == "" { + return "Empty" + } + + // Build the identifier with prefix handling + var result strings.Builder + prefix := c.getPrefix(name) + result.WriteString(prefix) + + // Convert the rest using word boundaries + capitalizeNext := exported || prefix != "" + prevWasDigit := false + for _, r := range name { + if c.isWordSeparator(r) { + capitalizeNext = true + prevWasDigit = false + continue + } + + if !unicode.IsLetter(r) && !unicode.IsDigit(r) { + // Skip invalid characters (already handled by prefix if at start) + capitalizeNext = true + prevWasDigit = false + continue + } + + // Capitalize after digits + if prevWasDigit && unicode.IsLetter(r) { + capitalizeNext = true + } + + if capitalizeNext && unicode.IsLetter(r) { + result.WriteRune(unicode.ToUpper(r)) + capitalizeNext = false + } else { + result.WriteRune(r) + } + + prevWasDigit = unicode.IsDigit(r) + } + + id := result.String() + if id == "" { + return "Empty" + } + + // Apply initialism fixes + id = c.applyInitialisms(id) + + return id +} + +// toGoIdentifierPart converts a name to a Go identifier component (for joining with others). +// It doesn't add a numeric prefix since the result won't necessarily be at the start of an identifier. +func (c *NameConverter) toGoIdentifierPart(name string) string { + if name == "" { + return "" + } + + // Build the identifier without numeric prefix (but still handle special characters at start) + var result strings.Builder + + // Only add prefix for non-digit special characters at the start + firstRune := []rune(name)[0] + if !unicode.IsLetter(firstRune) && !unicode.IsDigit(firstRune) { + firstChar := string(firstRune) + if sub, ok := c.mangling.CharacterSubstitutions[firstChar]; ok { + result.WriteString(sub) + } else { + result.WriteString("X") + } + } + + // Convert the rest using word boundaries (always capitalize since this is a part) + capitalizeNext := true + prevWasDigit := false + for _, r := range name { + if c.isWordSeparator(r) { + capitalizeNext = true + prevWasDigit = false + continue + } + + if !unicode.IsLetter(r) && !unicode.IsDigit(r) { + // Skip invalid characters (already handled by prefix if at start) + capitalizeNext = true + prevWasDigit = false + continue + } + + // Capitalize after digits + if prevWasDigit && unicode.IsLetter(r) { + capitalizeNext = true + } + + if capitalizeNext && unicode.IsLetter(r) { + result.WriteRune(unicode.ToUpper(r)) + capitalizeNext = false + } else { + result.WriteRune(r) + } + + prevWasDigit = unicode.IsDigit(r) + } + + id := result.String() + + // Apply initialism fixes + id = c.applyInitialisms(id) + + return id +} + +// getPrefix returns the prefix needed for names starting with invalid characters. +func (c *NameConverter) getPrefix(name string) string { + if name == "" { + return "" + } + + firstRune := []rune(name)[0] + + // Check if starts with digit + if unicode.IsDigit(firstRune) { + return c.mangling.NumericPrefix + } + + // Check if starts with letter (valid, no prefix needed) + if unicode.IsLetter(firstRune) { + return "" + } + + // Check character substitutions + firstChar := string(firstRune) + if sub, ok := c.mangling.CharacterSubstitutions[firstChar]; ok { + return sub + } + + // Unknown special character, use generic prefix + return "X" +} + +// isWordSeparator returns true if the rune is a word separator. +func (c *NameConverter) isWordSeparator(r rune) bool { + return strings.ContainsRune(c.mangling.WordSeparators, r) +} + +// applyInitialisms uppercases known initialisms in the identifier. +// It detects initialisms at word boundaries in PascalCase identifiers. +func (c *NameConverter) applyInitialisms(name string) string { + if len(name) == 0 { + return name + } + + // Split the identifier into "words" based on case transitions + // e.g., "UserId" -> ["User", "Id"], "HTTPUrl" -> ["HTTP", "Url"] + words := splitPascalCase(name) + + // Check each word against initialisms + for i, word := range words { + upper := strings.ToUpper(word) + if c.initialismSet[upper] { + words[i] = upper + } + } + + return strings.Join(words, "") +} + +// splitPascalCase splits a PascalCase identifier into words. +// e.g., "UserId" -> ["User", "Id"], "HTTPServer" -> ["HTTP", "Server"] +func splitPascalCase(s string) []string { + if len(s) == 0 { + return nil + } + + var words []string + var currentWord strings.Builder + + runes := []rune(s) + for i := 0; i < len(runes); i++ { + r := runes[i] + + if i == 0 { + currentWord.WriteRune(r) + continue + } + + prevUpper := unicode.IsUpper(runes[i-1]) + currUpper := unicode.IsUpper(r) + currDigit := unicode.IsDigit(r) + + // Start new word on: + // 1. Lowercase to uppercase transition (e.g., "userId" -> "user" | "Id") + // 2. Multiple uppercase followed by lowercase (e.g., "HTTPServer" -> "HTTP" | "Server") + if currUpper && !prevUpper { + // Lowercase to uppercase: start new word + words = append(words, currentWord.String()) + currentWord.Reset() + currentWord.WriteRune(r) + } else if currUpper && prevUpper && i+1 < len(runes) && unicode.IsLower(runes[i+1]) { + // Uppercase followed by lowercase, and previous was uppercase + // This is the start of a new word after an acronym + // e.g., in "HTTPServer", 'S' starts a new word + words = append(words, currentWord.String()) + currentWord.Reset() + currentWord.WriteRune(r) + } else if currDigit && !unicode.IsDigit(runes[i-1]) { + // Transition to digit: start new word + words = append(words, currentWord.String()) + currentWord.Reset() + currentWord.WriteRune(r) + } else if !currDigit && unicode.IsDigit(runes[i-1]) { + // Transition from digit: start new word + words = append(words, currentWord.String()) + currentWord.Reset() + currentWord.WriteRune(r) + } else { + currentWord.WriteRune(r) + } + } + + if currentWord.Len() > 0 { + words = append(words, currentWord.String()) + } + + return words +} diff --git a/experimental/internal/codegen/namemangling_test.go b/experimental/internal/codegen/namemangling_test.go new file mode 100644 index 0000000000..6d36cc0749 --- /dev/null +++ b/experimental/internal/codegen/namemangling_test.go @@ -0,0 +1,195 @@ +package codegen + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToTypeName(t *testing.T) { + c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) + + tests := []struct { + input string + expected string + }{ + // Basic conversions + {"foo", "Foo"}, + {"fooBar", "FooBar"}, + {"foo_bar", "FooBar"}, + {"foo-bar", "FooBar"}, + {"foo.bar", "FooBar"}, + + // Names starting with numbers + {"123", "N123"}, + {"123foo", "N123Foo"}, + {"1param", "N1Param"}, + + // Names starting with special characters + {"$ref", "DollarSignRef"}, + {"$", "DollarSign"}, + {"-1", "Minus1"}, + {"+1", "Plus1"}, + {"&now", "AndNow"}, + {"#tag", "HashTag"}, + {".hidden", "DotHidden"}, + {"@timestamp", "AtTimestamp"}, + {"_private", "UnderscorePrivate"}, + + // Initialisms + {"userId", "UserID"}, + {"httpUrl", "HTTPURL"}, + {"apiId", "APIID"}, + {"jsonData", "JSONData"}, + {"xmlParser", "XMLParser"}, + {"getHttpResponse", "GetHTTPResponse"}, + + // Go keywords - PascalCase doesn't conflict with lowercase keywords + {"type", "Type"}, + {"interface", "Interface"}, + {"map", "Map"}, + {"chan", "Chan"}, + + // Predeclared identifiers - PascalCase doesn't conflict with lowercase identifiers + {"string", "String"}, + {"int", "Int"}, + {"error", "Error"}, + {"nil", "Nil"}, + + // Edge cases + {"", "Empty"}, + {"a", "A"}, + {"A", "A"}, + {"ABC", "ABC"}, + {"myXMLParser", "MyXMLParser"}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := c.ToTypeName(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestToPropertyName(t *testing.T) { + c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) + + tests := []struct { + input string + expected string + }{ + {"user_id", "UserID"}, + {"created_at", "CreatedAt"}, + {"is_active", "IsActive"}, + {"123field", "N123Field"}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := c.ToPropertyName(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestToVariableName(t *testing.T) { + c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) + + tests := []struct { + input string + expected string + }{ + {"Foo", "foo"}, + {"FooBar", "fooBar"}, + {"user_id", "userID"}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := c.ToVariableName(tt.input) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestNameSubstitutions(t *testing.T) { + c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{ + TypeNames: map[string]string{ + "foo": "MyCustomFoo", + }, + PropertyNames: map[string]string{ + "bar": "MyCustomBar", + }, + }) + + assert.Equal(t, "MyCustomFoo", c.ToTypeName("foo")) + assert.Equal(t, "MyCustomBar", c.ToPropertyName("bar")) + + // Non-substituted names still work normally + assert.Equal(t, "Baz", c.ToTypeName("baz")) +} + +func TestCustomNameMangling(t *testing.T) { + // Custom config that changes numeric prefix + mangling := DefaultNameMangling() + mangling.NumericPrefix = "Num" + + c := NewNameConverter(mangling, NameSubstitutions{}) + + assert.Equal(t, "Num123", c.ToTypeName("123")) + assert.Equal(t, "Num1Foo", c.ToTypeName("1foo")) +} + +func TestMergeNameMangling(t *testing.T) { + defaults := DefaultNameMangling() + + // User wants to change just the numeric prefix + user := NameMangling{ + NumericPrefix: "Number", + } + + merged := defaults.Merge(user) + + // User value overrides + assert.Equal(t, "Number", merged.NumericPrefix) + + // Defaults preserved + assert.Equal(t, defaults.KeywordPrefix, merged.KeywordPrefix) + assert.Equal(t, defaults.WordSeparators, merged.WordSeparators) + assert.Equal(t, len(defaults.CharacterSubstitutions), len(merged.CharacterSubstitutions)) +} + +func TestMergeCharacterSubstitutions(t *testing.T) { + defaults := DefaultNameMangling() + + // User wants to override $ and add a new one + user := NameMangling{ + CharacterSubstitutions: map[string]string{ + "$": "Dollar", // Override default "DollarSign" + "€": "Euro", // Add new + }, + } + + merged := defaults.Merge(user) + + assert.Equal(t, "Dollar", merged.CharacterSubstitutions["$"]) + assert.Equal(t, "Euro", merged.CharacterSubstitutions["€"]) + assert.Equal(t, "Minus", merged.CharacterSubstitutions["-"]) // Default preserved +} + +func TestRemoveCharacterSubstitution(t *testing.T) { + defaults := DefaultNameMangling() + + // User wants to remove $ substitution (empty string = remove) + user := NameMangling{ + CharacterSubstitutions: map[string]string{ + "$": "", // Remove + }, + } + + merged := defaults.Merge(user) + + _, exists := merged.CharacterSubstitutions["$"] + assert.False(t, exists) +} diff --git a/experimental/internal/codegen/operation.go b/experimental/internal/codegen/operation.go new file mode 100644 index 0000000000..88cb4fe27a --- /dev/null +++ b/experimental/internal/codegen/operation.go @@ -0,0 +1,287 @@ +package codegen + +import ( + "strings" + + v3 "github.com/pb33f/libopenapi/datamodel/high/v3" +) + +// OperationSource indicates where an operation was defined in the spec. +type OperationSource string + +const ( + OperationSourcePath OperationSource = "path" + OperationSourceWebhook OperationSource = "webhook" + OperationSourceCallback OperationSource = "callback" +) + +// OperationDescriptor describes a single API operation from an OpenAPI spec. +type OperationDescriptor struct { + OperationID string // Normalized operation ID for function names + GoOperationID string // Go-safe identifier (handles leading digits, keywords) + Method string // HTTP method: GET, POST, PUT, DELETE, etc. + Path string // Original path: /users/{id} + Summary string // For generating comments + Description string // Longer description + + // Source indicates where this operation was defined (path, webhook, or callback) + Source OperationSource + WebhookName string // Webhook name (for Source=webhook) + CallbackName string // Callback key (for Source=callback) + ParentOpID string // Parent operation ID (for Source=callback) + + PathParams []*ParameterDescriptor + QueryParams []*ParameterDescriptor + HeaderParams []*ParameterDescriptor + CookieParams []*ParameterDescriptor + + Bodies []*RequestBodyDescriptor + Responses []*ResponseDescriptor + + Security []SecurityRequirement + + // Precomputed for templates + HasBody bool // Has at least one request body + HasParams bool // Has non-path params (needs Params struct) + ParamsTypeName string // "{OperationID}Params" + + // Reference to the underlying spec + Spec *v3.Operation +} + +// Params returns all non-path parameters (query, header, cookie). +// These are bundled into a Params struct. +func (o *OperationDescriptor) Params() []*ParameterDescriptor { + result := make([]*ParameterDescriptor, 0, len(o.QueryParams)+len(o.HeaderParams)+len(o.CookieParams)) + result = append(result, o.QueryParams...) + result = append(result, o.HeaderParams...) + result = append(result, o.CookieParams...) + return result +} + +// AllParams returns all parameters including path params. +func (o *OperationDescriptor) AllParams() []*ParameterDescriptor { + result := make([]*ParameterDescriptor, 0, len(o.PathParams)+len(o.QueryParams)+len(o.HeaderParams)+len(o.CookieParams)) + result = append(result, o.PathParams...) + result = append(result, o.QueryParams...) + result = append(result, o.HeaderParams...) + result = append(result, o.CookieParams...) + return result +} + +// SummaryAsComment returns the summary formatted as a Go comment. +func (o *OperationDescriptor) SummaryAsComment() string { + if o.Summary == "" { + return "" + } + trimmed := strings.TrimSuffix(o.Summary, "\n") + parts := strings.Split(trimmed, "\n") + for i, p := range parts { + parts[i] = "// " + p + } + return strings.Join(parts, "\n") +} + +// DefaultBody returns the default request body (typically application/json), or nil. +func (o *OperationDescriptor) DefaultBody() *RequestBodyDescriptor { + for _, b := range o.Bodies { + if b.IsDefault { + return b + } + } + if len(o.Bodies) > 0 { + return o.Bodies[0] + } + return nil +} + +// ParameterDescriptor describes a parameter in any location. +type ParameterDescriptor struct { + Name string // Original name from spec (e.g., "user_id") + GoName string // Go-safe name for struct fields (e.g., "UserId") + Location string // "path", "query", "header", "cookie" + Required bool + + // Serialization style + Style string // "simple", "form", "label", "matrix", etc. + Explode bool + + // Type information + Schema *SchemaDescriptor + TypeDecl string // Go type declaration (e.g., "string", "[]int", "*MyType") + + // Precomputed function names for templates + StyleFunc string // "StyleSimpleParam", "StyleFormExplodeParam", etc. + BindFunc string // "BindSimpleParam", "BindFormExplodeParam", etc. + + // Encoding modes + IsStyled bool // Uses style/explode serialization (most common) + IsPassThrough bool // No styling, just pass the string through + IsJSON bool // Parameter uses JSON content encoding + + Spec *v3.Parameter +} + +// GoVariableName returns a Go-safe variable name for this parameter. +// Used for local variables in generated code. +func (p *ParameterDescriptor) GoVariableName() string { + name := LowercaseFirstCharacter(p.GoName) + if IsGoKeyword(name) { + name = "p" + p.GoName + } + // Handle leading digits + if len(name) > 0 && name[0] >= '0' && name[0] <= '9' { + name = "n" + name + } + return name +} + +// HasOptionalPointer returns true if this parameter should be a pointer +// (optional parameters that aren't required). +func (p *ParameterDescriptor) HasOptionalPointer() bool { + if p.Required { + return false + } + // Check if schema has skip-optional-pointer extension + if p.Schema != nil && p.Schema.Extensions != nil && + p.Schema.Extensions.SkipOptionalPointer != nil && *p.Schema.Extensions.SkipOptionalPointer { + return false + } + return true +} + +// RequestBodyDescriptor describes a request body for a specific content type. +type RequestBodyDescriptor struct { + ContentType string // "application/json", "multipart/form-data", etc. + Required bool + Schema *SchemaDescriptor + + // Precomputed for templates + NameTag string // "JSON", "Formdata", "Multipart", "Text", etc. + GoTypeName string // "{OperationID}JSONBody", etc. + FuncSuffix string // "", "WithJSONBody", "WithFormBody" (empty for default) + IsDefault bool // Is this the default body type? + IsJSON bool // Is this a JSON content type? + + // Encoding options for form data + Encoding map[string]RequestBodyEncoding +} + +// RequestBodyEncoding describes encoding options for a form field. +type RequestBodyEncoding struct { + ContentType string + Style string + Explode *bool +} + +// ResponseDescriptor describes a response for a status code. +type ResponseDescriptor struct { + StatusCode string // "200", "404", "default", "2XX" + Description string + Contents []*ResponseContentDescriptor + Headers []*ResponseHeaderDescriptor + Ref string // If this is a reference to a named response +} + +// GoName returns a Go-safe name for this response (e.g., "200" -> "200", "default" -> "Default"). +func (r *ResponseDescriptor) GoName() string { + return ToCamelCase(r.StatusCode) +} + +// HasFixedStatusCode returns true if the status code is a specific number (not "default" or "2XX"). +func (r *ResponseDescriptor) HasFixedStatusCode() bool { + if r.StatusCode == "default" { + return false + } + // Check for wildcard patterns like "2XX" + if strings.HasSuffix(strings.ToUpper(r.StatusCode), "XX") { + return false + } + return true +} + +// ResponseContentDescriptor describes response content for a content type. +type ResponseContentDescriptor struct { + ContentType string + Schema *SchemaDescriptor + NameTag string // "JSON", "XML", etc. + IsJSON bool +} + +// ResponseHeaderDescriptor describes a response header. +type ResponseHeaderDescriptor struct { + Name string + GoName string + Required bool + Schema *SchemaDescriptor +} + +// SecurityRequirement describes a security requirement for an operation. +type SecurityRequirement struct { + Name string // Security scheme name + Scopes []string // Required scopes (for OAuth2) +} + +// Helper functions for computing descriptor fields + +// ComputeStyleFunc returns the style function name for a parameter. +func ComputeStyleFunc(style string, explode bool) string { + base := "Style" + ToCamelCase(style) + if explode { + return base + "ExplodeParam" + } + return base + "Param" +} + +// ComputeBindFunc returns the bind function name for a parameter. +func ComputeBindFunc(style string, explode bool) string { + base := "Bind" + ToCamelCase(style) + if explode { + return base + "ExplodeParam" + } + return base + "Param" +} + +// ComputeBodyNameTag returns the name tag for a content type. +func ComputeBodyNameTag(contentType string) string { + switch { + case contentType == "application/json": + return "JSON" + case IsMediaTypeJSON(contentType): + return MediaTypeToCamelCase(contentType) + case strings.HasPrefix(contentType, "multipart/"): + return "Multipart" + case contentType == "application/x-www-form-urlencoded": + return "Formdata" + case contentType == "text/plain": + return "Text" + case strings.HasPrefix(contentType, "application/xml") || strings.HasSuffix(contentType, "+xml"): + return "XML" + default: + return "" + } +} + +// IsMediaTypeJSON returns true if the content type is a JSON media type. +func IsMediaTypeJSON(contentType string) bool { + if contentType == "application/json" { + return true + } + if strings.HasSuffix(contentType, "+json") { + return true + } + if strings.Contains(contentType, "json") { + return true + } + return false +} + +// MediaTypeToCamelCase converts a media type to a CamelCase identifier. +func MediaTypeToCamelCase(mediaType string) string { + // application/vnd.api+json -> ApplicationVndApiJson + mediaType = strings.ReplaceAll(mediaType, "/", " ") + mediaType = strings.ReplaceAll(mediaType, "+", " ") + mediaType = strings.ReplaceAll(mediaType, ".", " ") + mediaType = strings.ReplaceAll(mediaType, "-", " ") + return ToCamelCase(mediaType) +} diff --git a/experimental/internal/codegen/output.go b/experimental/internal/codegen/output.go new file mode 100644 index 0000000000..0793124223 --- /dev/null +++ b/experimental/internal/codegen/output.go @@ -0,0 +1,764 @@ +package codegen + +import ( + "bytes" + "fmt" + "sort" + "strings" + + "golang.org/x/tools/imports" +) + +// Output collects generated Go code and formats it. +type Output struct { + packageName string + imports map[string]string // path -> alias + types []string // type definitions in order +} + +// NewOutput creates a new output collector. +func NewOutput(packageName string) *Output { + return &Output{ + packageName: packageName, + imports: make(map[string]string), + } +} + +// AddImport adds an import path with optional alias. +func (o *Output) AddImport(path, alias string) { + if path == "" { + return + } + o.imports[path] = alias +} + +// AddImports adds multiple imports from a map. +func (o *Output) AddImports(imports map[string]string) { + for path, alias := range imports { + o.AddImport(path, alias) + } +} + +// AddType adds a type definition to the output. +func (o *Output) AddType(code string) { + if code != "" { + o.types = append(o.types, code) + } +} + +// String generates the complete Go source file. +func (o *Output) String() string { + var buf bytes.Buffer + + // Generated code header (tells linters to skip this file) + buf.WriteString("// Code generated by oapi-codegen; DO NOT EDIT.\n\n") + + // Package declaration + fmt.Fprintf(&buf, "package %s\n\n", o.packageName) + + // Imports + if len(o.imports) > 0 { + buf.WriteString("import (\n") + paths := make([]string, 0, len(o.imports)) + for path := range o.imports { + paths = append(paths, path) + } + sort.Strings(paths) + + for _, path := range paths { + alias := o.imports[path] + if alias != "" { + fmt.Fprintf(&buf, "\t%s %q\n", alias, path) + } else { + fmt.Fprintf(&buf, "\t%q\n", path) + } + } + buf.WriteString(")\n\n") + } + + // Types + for _, t := range o.types { + buf.WriteString(t) + buf.WriteString("\n\n") + } + + return buf.String() +} + +// Format returns the formatted Go source code with imports organized. +func (o *Output) Format() (string, error) { + src := o.String() + formatted, err := imports.Process("", []byte(src), nil) + if err != nil { + return src, fmt.Errorf("formatting output: %w (source:\n%s)", err, src) + } + return string(formatted), nil +} + +// CodeBuilder helps construct Go code fragments. +type CodeBuilder struct { + buf bytes.Buffer + indent int +} + +// NewCodeBuilder creates a new code builder. +func NewCodeBuilder() *CodeBuilder { + return &CodeBuilder{} +} + +// Indent increases indentation. +func (b *CodeBuilder) Indent() { + b.indent++ +} + +// Dedent decreases indentation. +func (b *CodeBuilder) Dedent() { + if b.indent > 0 { + b.indent-- + } +} + +// Line writes a line with current indentation. +func (b *CodeBuilder) Line(format string, args ...any) { + for i := 0; i < b.indent; i++ { + b.buf.WriteByte('\t') + } + if len(args) > 0 { + fmt.Fprintf(&b.buf, format, args...) + } else { + b.buf.WriteString(format) + } + b.buf.WriteByte('\n') +} + +// BlankLine writes an empty line. +func (b *CodeBuilder) BlankLine() { + b.buf.WriteByte('\n') +} + +// Raw writes raw text without indentation or newline. +func (b *CodeBuilder) Raw(s string) { + b.buf.WriteString(s) +} + +// String returns the built code. +func (b *CodeBuilder) String() string { + return b.buf.String() +} + +// GenerateStruct generates a struct type definition. +func GenerateStruct(name string, fields []StructField, doc string, tagGen *StructTagGenerator) string { + b := NewCodeBuilder() + + // Type documentation + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + b.Line("type %s struct {", name) + b.Indent() + + for _, f := range fields { + tag := generateFieldTag(f, tagGen) + if f.Doc != "" { + // Single line comment for field + b.Line("%s %s %s // %s", f.Name, f.Type, tag, f.Doc) + } else { + b.Line("%s %s %s", f.Name, f.Type, tag) + } + } + + b.Dedent() + b.Line("}") + + return b.String() +} + +// generateFieldTag generates the struct tag for a field. +func generateFieldTag(f StructField, tagGen *StructTagGenerator) string { + if tagGen == nil { + if f.JSONIgnore { + return "`json:\"-\"`" + } + return FormatJSONTag(f.JSONName, f.OmitEmpty) + } + info := StructTagInfo{ + FieldName: f.JSONName, + GoFieldName: f.Name, + IsOptional: !f.Required, + IsNullable: f.Nullable, + IsPointer: f.Pointer, + OmitEmpty: f.OmitEmpty, + OmitZero: f.OmitZero, + JSONIgnore: f.JSONIgnore, + } + return tagGen.GenerateTags(info) +} + +// GenerateStructWithAdditionalProps generates a struct with AdditionalProperties field +// and custom marshal/unmarshal methods. +func GenerateStructWithAdditionalProps(name string, fields []StructField, addPropsType string, doc string, tagGen *StructTagGenerator) string { + b := NewCodeBuilder() + + // Type documentation + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + b.Line("type %s struct {", name) + b.Indent() + + // Regular fields + for _, f := range fields { + tag := generateFieldTag(f, tagGen) + b.Line("%s %s %s", f.Name, f.Type, tag) + } + + // AdditionalProperties field + b.Line("AdditionalProperties map[string]%s `json:\"-\"`", addPropsType) + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateTypeAlias generates a type alias definition. +func GenerateTypeAlias(name, targetType, doc string) string { + b := NewCodeBuilder() + + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + b.Line("type %s = %s", name, targetType) + + return b.String() +} + +// GenerateEnum generates an enum type with const values. +// If customNames is provided and has the same length as values, those names will be used +// as the constant names instead of auto-generated ones. +func GenerateEnum(name, baseType string, values []string, customNames []string, doc string) string { + return GenerateEnumWithConstPrefix(name, name, baseType, values, customNames, doc) +} + +// GenerateEnumWithConstPrefix generates an enum type with const values. +// typeName is used for the type definition, constPrefix is used for constant names. +// This allows the type to be defined with a stable name while constants use a friendly name. +func GenerateEnumWithConstPrefix(typeName, constPrefix, baseType string, values []string, customNames []string, doc string) string { + b := NewCodeBuilder() + + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + b.Line("type %s %s", typeName, baseType) + b.BlankLine() + + if len(values) > 0 { + b.Line("const (") + b.Indent() + + // Track used names to handle duplicates + usedNames := make(map[string]int) + + for i, v := range values { + var constName string + + // Use custom name if provided, otherwise auto-generate + if len(customNames) > i && customNames[i] != "" { + constName = constPrefix + "_" + customNames[i] + } else { + constSuffix := sanitizeEnumValue(v, baseType) + constName = constPrefix + "_" + constSuffix + } + + // Handle duplicate names by adding a numeric suffix + if count, exists := usedNames[constName]; exists { + constName = fmt.Sprintf("%s_%d", constName, count) + usedNames[constName] = count + 1 + } else { + usedNames[constName] = 1 + } + + if baseType == "string" { + b.Line("%s %s = %q", constName, typeName, v) + } else { + b.Line("%s %s = %s", constName, typeName, v) + } + } + + b.Dedent() + b.Line(")") + } + + return b.String() +} + +// sanitizeEnumValue converts an enum value to a valid Go identifier suffix. +func sanitizeEnumValue(v string, baseType string) string { + // For integer enums, prefix with N for readability + if baseType == "int" || baseType == "int32" || baseType == "int64" { + // Check if it's a numeric value + if len(v) > 0 { + firstChar := v[0] + if firstChar >= '0' && firstChar <= '9' || firstChar == '-' { + // Negative numbers + if firstChar == '-' { + return "Minus" + v[1:] + } + return "N" + v + } + } + } + + // Replace common special characters + v = strings.ReplaceAll(v, "-", "_") + v = strings.ReplaceAll(v, " ", "_") + v = strings.ReplaceAll(v, ".", "_") + + // Remove any remaining invalid characters + var result strings.Builder + for i, r := range v { + if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r == '_' { + result.WriteRune(r) + } else if r >= '0' && r <= '9' && i > 0 { + result.WriteRune(r) + } + } + + if result.Len() == 0 { + return "Value" + } + return result.String() +} + +// GenerateUnionType generates a union struct for anyOf/oneOf with marshal/unmarshal. +func GenerateUnionType(name string, members []UnionMember, isOneOf bool, doc string) string { + b := NewCodeBuilder() + + if doc != "" { + for _, line := range strings.Split(doc, "\n") { + b.Line("// %s", line) + } + } + + // Generate struct with pointer field for each member + b.Line("type %s struct {", name) + b.Indent() + + for _, m := range members { + b.Line("%s *%s", m.FieldName, m.TypeName) + } + + b.Dedent() + b.Line("}") + + return b.String() +} + +// UnionMember represents a member of a union type (anyOf/oneOf). +type UnionMember struct { + FieldName string // Go field name + TypeName string // Go type name + Index int // Position in anyOf/oneOf array + HasApplyDefaults bool // Whether this type has an ApplyDefaults method +} + +// isPrimitiveType returns true if the type is a Go primitive or collection +// that doesn't have an ApplyDefaults method. +func isPrimitiveType(typeName string) bool { + switch typeName { + case "string", "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", + "float32", "float64", "bool", "any": + return true + default: + // Slices and maps don't have ApplyDefaults + if strings.HasPrefix(typeName, "[]") || strings.HasPrefix(typeName, "map[") { + return true + } + return false + } +} + +// GenerateUnionApplyDefaults generates ApplyDefaults for a union type. +// It recurses into non-nil members that have ApplyDefaults. +func GenerateUnionApplyDefaults(name string, members []UnionMember) string { + b := NewCodeBuilder() + + b.Line("// ApplyDefaults sets default values for fields that are nil.") + b.Line("func (u *%s) ApplyDefaults() {", name) + b.Indent() + + for _, m := range members { + // Only recurse into types that have ApplyDefaults + if m.HasApplyDefaults { + b.Line("if u.%s != nil {", m.FieldName) + b.Indent() + b.Line("u.%s.ApplyDefaults()", m.FieldName) + b.Dedent() + b.Line("}") + } + } + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateUnionMarshalOneOf generates MarshalJSON for a oneOf type. +func GenerateUnionMarshalOneOf(name string, members []UnionMember) string { + b := NewCodeBuilder() + + b.Line("func (u %s) MarshalJSON() ([]byte, error) {", name) + b.Indent() + + b.Line("var count int") + b.Line("var data []byte") + b.Line("var err error") + b.BlankLine() + + for _, m := range members { + b.Line("if u.%s != nil {", m.FieldName) + b.Indent() + b.Line("count++") + b.Line("data, err = json.Marshal(u.%s)", m.FieldName) + b.Line("if err != nil {") + b.Indent() + b.Line("return nil, err") + b.Dedent() + b.Line("}") + b.Dedent() + b.Line("}") + } + + b.BlankLine() + b.Line("if count != 1 {") + b.Indent() + b.Line("return nil, fmt.Errorf(\"%s: exactly one member must be set, got %%d\", count)", name) + b.Dedent() + b.Line("}") + b.BlankLine() + b.Line("return data, nil") + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateUnionUnmarshalOneOf generates UnmarshalJSON for a oneOf type. +func GenerateUnionUnmarshalOneOf(name string, members []UnionMember) string { + b := NewCodeBuilder() + + b.Line("func (u *%s) UnmarshalJSON(data []byte) error {", name) + b.Indent() + + b.Line("var successCount int") + b.BlankLine() + + for _, m := range members { + b.Line("var v%d %s", m.Index, m.TypeName) + b.Line("if err := json.Unmarshal(data, &v%d); err == nil {", m.Index) + b.Indent() + b.Line("u.%s = &v%d", m.FieldName, m.Index) + b.Line("successCount++") + b.Dedent() + b.Line("}") + b.BlankLine() + } + + b.Line("if successCount != 1 {") + b.Indent() + b.Line("return fmt.Errorf(\"%s: expected exactly one type to match, got %%d\", successCount)", name) + b.Dedent() + b.Line("}") + b.BlankLine() + b.Line("return nil") + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateUnionMarshalAnyOf generates MarshalJSON for an anyOf type. +func GenerateUnionMarshalAnyOf(name string, members []UnionMember) string { + b := NewCodeBuilder() + + b.Line("func (u %s) MarshalJSON() ([]byte, error) {", name) + b.Indent() + + // Check if any members are objects (need field merging) + hasObjects := false + for _, m := range members { + if !isPrimitiveType(m.TypeName) { + hasObjects = true + break + } + } + + if hasObjects { + // Merge object fields + b.Line("result := make(map[string]any)") + b.BlankLine() + + for _, m := range members { + b.Line("if u.%s != nil {", m.FieldName) + b.Indent() + if isPrimitiveType(m.TypeName) { + // For primitives, we can't merge - just return the value + b.Line("return json.Marshal(u.%s)", m.FieldName) + } else { + b.Line("data, err := json.Marshal(u.%s)", m.FieldName) + b.Line("if err != nil {") + b.Indent() + b.Line("return nil, err") + b.Dedent() + b.Line("}") + b.Line("var m map[string]any") + b.Line("if err := json.Unmarshal(data, &m); err == nil {") + b.Indent() + b.Line("for k, v := range m {") + b.Indent() + b.Line("result[k] = v") + b.Dedent() + b.Line("}") + b.Dedent() + b.Line("}") + } + b.Dedent() + b.Line("}") + } + + b.BlankLine() + b.Line("return json.Marshal(result)") + } else { + // All primitives - marshal the first non-nil one + for _, m := range members { + b.Line("if u.%s != nil {", m.FieldName) + b.Indent() + b.Line("return json.Marshal(u.%s)", m.FieldName) + b.Dedent() + b.Line("}") + } + b.Line("return []byte(\"null\"), nil") + } + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateUnionUnmarshalAnyOf generates UnmarshalJSON for an anyOf type. +func GenerateUnionUnmarshalAnyOf(name string, members []UnionMember) string { + b := NewCodeBuilder() + + b.Line("func (u *%s) UnmarshalJSON(data []byte) error {", name) + b.Indent() + + for _, m := range members { + b.Line("var v%d %s", m.Index, m.TypeName) + b.Line("if err := json.Unmarshal(data, &v%d); err == nil {", m.Index) + b.Indent() + b.Line("u.%s = &v%d", m.FieldName, m.Index) + b.Dedent() + b.Line("}") + b.BlankLine() + } + + b.Line("return nil") + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateMixedPropertiesMarshal generates MarshalJSON for structs with additionalProperties. +func GenerateMixedPropertiesMarshal(name string, fields []StructField) string { + b := NewCodeBuilder() + + b.Line("func (s %s) MarshalJSON() ([]byte, error) {", name) + b.Indent() + + b.Line("result := make(map[string]any)") + b.BlankLine() + + // Copy known fields + for _, f := range fields { + if f.Pointer { + b.Line("if s.%s != nil {", f.Name) + b.Indent() + b.Line("result[%q] = s.%s", f.JSONName, f.Name) + b.Dedent() + b.Line("}") + } else { + b.Line("result[%q] = s.%s", f.JSONName, f.Name) + } + } + + b.BlankLine() + b.Line("// Add additional properties") + b.Line("for k, v := range s.AdditionalProperties {") + b.Indent() + b.Line("result[k] = v") + b.Dedent() + b.Line("}") + b.BlankLine() + b.Line("return json.Marshal(result)") + + b.Dedent() + b.Line("}") + + return b.String() +} + +// GenerateApplyDefaults generates an ApplyDefaults method for a struct. +// It sets default values for fields that are nil and have defaults defined, +// and recursively calls ApplyDefaults on nested struct fields. +// Always generates the method (even if empty) so it can be called uniformly. +func GenerateApplyDefaults(name string, fields []StructField) string { + b := NewCodeBuilder() + + b.Line("// ApplyDefaults sets default values for fields that are nil.") + b.Line("func (s *%s) ApplyDefaults() {", name) + b.Indent() + + for _, f := range fields { + // Apply defaults to nil pointer fields + if f.Default != "" && f.Pointer { + b.Line("if s.%s == nil {", f.Name) + b.Indent() + // Get the base type (without *) + baseType := strings.TrimPrefix(f.Type, "*") + // Check if we need an explicit type conversion for numeric types + // This is needed because Go infers float64 for floating point literals + // and int for integer literals, which may not match the target type + if needsTypeConversion(baseType) { + b.Line("v := %s(%s)", baseType, f.Default) + } else { + b.Line("v := %s", f.Default) + } + b.Line("s.%s = &v", f.Name) + b.Dedent() + b.Line("}") + } + + // Recursively apply defaults to struct fields + if f.IsStruct && f.Pointer { + b.Line("if s.%s != nil {", f.Name) + b.Indent() + b.Line("s.%s.ApplyDefaults()", f.Name) + b.Dedent() + b.Line("}") + } + } + + b.Dedent() + b.Line("}") + + return b.String() +} + +// needsTypeConversion returns true if a numeric type needs an explicit conversion +// from the default Go literal type (int for integers, float64 for floats). +func needsTypeConversion(goType string) bool { + switch goType { + case "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", + "float32": + return true + default: + return false + } +} + +// GenerateMixedPropertiesUnmarshal generates UnmarshalJSON for structs with additionalProperties. +func GenerateMixedPropertiesUnmarshal(name string, fields []StructField, addPropsType string) string { + b := NewCodeBuilder() + + b.Line("func (s *%s) UnmarshalJSON(data []byte) error {", name) + b.Indent() + + // Build set of known field names + b.Line("// Known fields") + b.Line("knownFields := map[string]bool{") + b.Indent() + for _, f := range fields { + b.Line("%q: true,", f.JSONName) + } + b.Dedent() + b.Line("}") + b.BlankLine() + + // Unmarshal into a map first + b.Line("var raw map[string]json.RawMessage") + b.Line("if err := json.Unmarshal(data, &raw); err != nil {") + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.BlankLine() + + // Unmarshal known fields + for _, f := range fields { + b.Line("if v, ok := raw[%q]; ok {", f.JSONName) + b.Indent() + if f.Pointer { + b.Line("var val %s", strings.TrimPrefix(f.Type, "*")) + b.Line("if err := json.Unmarshal(v, &val); err != nil {") + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.Line("s.%s = &val", f.Name) + } else { + b.Line("if err := json.Unmarshal(v, &s.%s); err != nil {", f.Name) + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + } + b.Dedent() + b.Line("}") + } + + b.BlankLine() + b.Line("// Collect additional properties") + b.Line("s.AdditionalProperties = make(map[string]%s)", addPropsType) + b.Line("for k, v := range raw {") + b.Indent() + b.Line("if !knownFields[k] {") + b.Indent() + b.Line("var val %s", addPropsType) + b.Line("if err := json.Unmarshal(v, &val); err != nil {") + b.Indent() + b.Line("return err") + b.Dedent() + b.Line("}") + b.Line("s.AdditionalProperties[k] = val") + b.Dedent() + b.Line("}") + b.Dedent() + b.Line("}") + b.BlankLine() + b.Line("return nil") + + b.Dedent() + b.Line("}") + + return b.String() +} diff --git a/experimental/internal/codegen/paramgen.go b/experimental/internal/codegen/paramgen.go new file mode 100644 index 0000000000..19221ac0c0 --- /dev/null +++ b/experimental/internal/codegen/paramgen.go @@ -0,0 +1,178 @@ +package codegen + +import ( + "fmt" + "sort" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// ParamUsageTracker tracks which parameter styling and binding functions +// are needed based on the OpenAPI spec being processed. +type ParamUsageTracker struct { + // usedStyles tracks which style/explode combinations are used. + // Keys are formatted as "style_{style}" or "style_{style}_explode" for serialization, + // and "bind_{style}" or "bind_{style}_explode" for binding. + usedStyles map[string]bool +} + +// NewParamUsageTracker creates a new ParamUsageTracker. +func NewParamUsageTracker() *ParamUsageTracker { + return &ParamUsageTracker{ + usedStyles: make(map[string]bool), + } +} + +// RecordStyleParam records that a style/explode combination is used for serialization. +// This is typically called when processing client parameters. +func (t *ParamUsageTracker) RecordStyleParam(style string, explode bool) { + key := templates.ParamStyleKey("style_", style, explode) + t.usedStyles[key] = true +} + +// RecordBindParam records that a style/explode combination is used for binding. +// This is typically called when processing server parameters. +func (t *ParamUsageTracker) RecordBindParam(style string, explode bool) { + key := templates.ParamStyleKey("bind_", style, explode) + t.usedStyles[key] = true +} + +// RecordParam records both style and bind usage for a parameter. +// Use this when generating both client and server code. +func (t *ParamUsageTracker) RecordParam(style string, explode bool) { + t.RecordStyleParam(style, explode) + t.RecordBindParam(style, explode) +} + +// HasAnyUsage returns true if any parameter functions are needed. +func (t *ParamUsageTracker) HasAnyUsage() bool { + return len(t.usedStyles) > 0 +} + +// GetRequiredTemplates returns the list of templates needed based on usage. +// The helpers template is always included first if any functions are needed. +func (t *ParamUsageTracker) GetRequiredTemplates() []templates.ParamTemplate { + if !t.HasAnyUsage() { + return nil + } + + var result []templates.ParamTemplate + + // Always include helpers first + result = append(result, templates.ParamHelpersTemplate) + + // Get all used style keys and sort them for deterministic output + keys := make([]string, 0, len(t.usedStyles)) + for key := range t.usedStyles { + keys = append(keys, key) + } + sort.Strings(keys) + + // Add each required template + for _, key := range keys { + tmpl, ok := templates.ParamTemplates[key] + if !ok { + // This shouldn't happen if keys are properly validated + continue + } + result = append(result, tmpl) + } + + return result +} + +// GetRequiredImports returns all imports needed for the used parameter functions. +// This aggregates imports from the helpers template and all used templates. +func (t *ParamUsageTracker) GetRequiredImports() []templates.Import { + if !t.HasAnyUsage() { + return nil + } + + // Use a map to deduplicate imports + importSet := make(map[string]templates.Import) + + // Add helpers imports + for _, imp := range templates.ParamHelpersTemplate.Imports { + importSet[imp.Path] = imp + } + + // Add imports from each used template + for key := range t.usedStyles { + tmpl, ok := templates.ParamTemplates[key] + if !ok { + continue + } + for _, imp := range tmpl.Imports { + importSet[imp.Path] = imp + } + } + + // Convert to sorted slice + result := make([]templates.Import, 0, len(importSet)) + for _, imp := range importSet { + result = append(result, imp) + } + sort.Slice(result, func(i, j int) bool { + return result[i].Path < result[j].Path + }) + + return result +} + +// GetUsedStyleKeys returns the sorted list of used style keys for debugging. +func (t *ParamUsageTracker) GetUsedStyleKeys() []string { + keys := make([]string, 0, len(t.usedStyles)) + for key := range t.usedStyles { + keys = append(keys, key) + } + sort.Strings(keys) + return keys +} + +// DefaultParamStyle returns the default style for a parameter location. +func DefaultParamStyle(location string) string { + switch location { + case "path", "header": + return "simple" + case "query", "cookie": + return "form" + default: + return "form" + } +} + +// DefaultParamExplode returns the default explode value for a parameter location. +func DefaultParamExplode(location string) bool { + switch location { + case "path", "header": + return false + case "query", "cookie": + return true + default: + return false + } +} + +// ValidateParamStyle validates that a style is supported for a location. +// Returns an error if the combination is invalid. +func ValidateParamStyle(style, location string) error { + validStyles := map[string][]string{ + "path": {"simple", "label", "matrix"}, + "query": {"form", "spaceDelimited", "pipeDelimited", "deepObject"}, + "header": {"simple"}, + "cookie": {"form"}, + } + + allowed, ok := validStyles[location] + if !ok { + return fmt.Errorf("unknown parameter location: %s", location) + } + + for _, s := range allowed { + if s == style { + return nil + } + } + + return fmt.Errorf("style '%s' is not valid for location '%s'; valid styles are: %v", style, location, allowed) +} diff --git a/experimental/internal/codegen/paramgen_test.go b/experimental/internal/codegen/paramgen_test.go new file mode 100644 index 0000000000..a80de1e40d --- /dev/null +++ b/experimental/internal/codegen/paramgen_test.go @@ -0,0 +1,161 @@ +package codegen + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParamUsageTracker(t *testing.T) { + t.Run("empty tracker has no usage", func(t *testing.T) { + tracker := NewParamUsageTracker() + assert.False(t, tracker.HasAnyUsage()) + assert.Empty(t, tracker.GetRequiredTemplates()) + assert.Empty(t, tracker.GetRequiredImports()) + }) + + t.Run("records style param", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordStyleParam("simple", false) + + assert.True(t, tracker.HasAnyUsage()) + keys := tracker.GetUsedStyleKeys() + assert.Contains(t, keys, "style_simple") + }) + + t.Run("records style param with explode", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordStyleParam("form", true) + + keys := tracker.GetUsedStyleKeys() + assert.Contains(t, keys, "style_form_explode") + }) + + t.Run("records bind param", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordBindParam("label", false) + + keys := tracker.GetUsedStyleKeys() + assert.Contains(t, keys, "bind_label") + }) + + t.Run("records both style and bind", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordParam("matrix", true) + + keys := tracker.GetUsedStyleKeys() + assert.Contains(t, keys, "style_matrix_explode") + assert.Contains(t, keys, "bind_matrix_explode") + }) + + t.Run("returns helpers template first", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordStyleParam("simple", false) + + templates := tracker.GetRequiredTemplates() + require.NotEmpty(t, templates) + assert.Equal(t, "helpers", templates[0].Name) + }) + + t.Run("aggregates imports", func(t *testing.T) { + tracker := NewParamUsageTracker() + tracker.RecordStyleParam("simple", false) + tracker.RecordStyleParam("form", true) + + imports := tracker.GetRequiredImports() + assert.NotEmpty(t, imports) + + // Check that common imports are included + paths := make([]string, len(imports)) + for i, imp := range imports { + paths[i] = imp.Path + } + assert.Contains(t, paths, "reflect") + assert.Contains(t, paths, "strings") + }) +} + +func TestDefaultParamStyle(t *testing.T) { + tests := []struct { + location string + expected string + }{ + {"path", "simple"}, + {"header", "simple"}, + {"query", "form"}, + {"cookie", "form"}, + {"unknown", "form"}, + } + + for _, tc := range tests { + t.Run(tc.location, func(t *testing.T) { + assert.Equal(t, tc.expected, DefaultParamStyle(tc.location)) + }) + } +} + +func TestDefaultParamExplode(t *testing.T) { + tests := []struct { + location string + expected bool + }{ + {"path", false}, + {"header", false}, + {"query", true}, + {"cookie", true}, + {"unknown", false}, + } + + for _, tc := range tests { + t.Run(tc.location, func(t *testing.T) { + assert.Equal(t, tc.expected, DefaultParamExplode(tc.location)) + }) + } +} + +func TestValidateParamStyle(t *testing.T) { + validCases := []struct { + style string + location string + }{ + {"simple", "path"}, + {"label", "path"}, + {"matrix", "path"}, + {"form", "query"}, + {"spaceDelimited", "query"}, + {"pipeDelimited", "query"}, + {"deepObject", "query"}, + {"simple", "header"}, + {"form", "cookie"}, + } + + for _, tc := range validCases { + t.Run(tc.style+"_in_"+tc.location, func(t *testing.T) { + err := ValidateParamStyle(tc.style, tc.location) + assert.NoError(t, err) + }) + } + + invalidCases := []struct { + style string + location string + }{ + {"deepObject", "path"}, + {"matrix", "query"}, + {"label", "header"}, + {"simple", "cookie"}, + } + + for _, tc := range invalidCases { + t.Run(tc.style+"_in_"+tc.location+"_invalid", func(t *testing.T) { + err := ValidateParamStyle(tc.style, tc.location) + assert.Error(t, err) + }) + } + + t.Run("unknown location", func(t *testing.T) { + err := ValidateParamStyle("simple", "body") + assert.Error(t, err) + }) +} diff --git a/experimental/internal/codegen/receivergen.go b/experimental/internal/codegen/receivergen.go new file mode 100644 index 0000000000..e57fef3929 --- /dev/null +++ b/experimental/internal/codegen/receivergen.go @@ -0,0 +1,131 @@ +package codegen + +import ( + "bytes" + "fmt" + "strings" + "text/template" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// ReceiverTemplateData is passed to receiver templates. +type ReceiverTemplateData struct { + Prefix string // "Webhook" or "Callback" + PrefixLower string // "webhook" or "callback" + Operations []*OperationDescriptor // Operations to generate for +} + +// ReceiverGenerator generates receiver code from operation descriptors. +// It is parameterized by prefix to support both webhooks and callbacks. +type ReceiverGenerator struct { + tmpl *template.Template + prefix string // "Webhook" or "Callback" + serverType string +} + +// NewReceiverGenerator creates a new receiver generator for the specified server type. +func NewReceiverGenerator(prefix string, serverType string) (*ReceiverGenerator, error) { + if serverType == "" { + return nil, fmt.Errorf("%s receiver requires a server type to be set", prefix) + } + + tmpl := template.New("receiver").Funcs(templates.Funcs()) + + // Get receiver templates for the specified server type + receiverTemplates, err := getReceiverTemplates(serverType) + if err != nil { + return nil, err + } + + // Parse receiver-specific templates + for _, ct := range receiverTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + ct.Template) + if err != nil { + return nil, fmt.Errorf("failed to read receiver template %s: %w", ct.Template, err) + } + _, err = tmpl.New(ct.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse receiver template %s: %w", ct.Template, err) + } + } + + // Parse shared templates (errors, param_types) + for _, st := range templates.SharedServerTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + st.Template) + if err != nil { + return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) + } + _, err = tmpl.New(st.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) + } + } + + return &ReceiverGenerator{ + tmpl: tmpl, + prefix: prefix, + serverType: serverType, + }, nil +} + +// getReceiverTemplates returns the receiver templates for the specified server type. +func getReceiverTemplates(serverType string) (map[string]templates.ReceiverTemplate, error) { + switch serverType { + case ServerTypeStdHTTP: + return templates.StdHTTPReceiverTemplates, nil + case ServerTypeChi: + return templates.ChiReceiverTemplates, nil + case ServerTypeEcho: + return templates.EchoReceiverTemplates, nil + case ServerTypeEchoV4: + return templates.EchoV4ReceiverTemplates, nil + case ServerTypeGin: + return templates.GinReceiverTemplates, nil + case ServerTypeGorilla: + return templates.GorillaReceiverTemplates, nil + case ServerTypeFiber: + return templates.FiberReceiverTemplates, nil + case ServerTypeIris: + return templates.IrisReceiverTemplates, nil + default: + return nil, fmt.Errorf("unsupported server type for receiver: %q", serverType) + } +} + +func (g *ReceiverGenerator) templateData(ops []*OperationDescriptor) ReceiverTemplateData { + return ReceiverTemplateData{ + Prefix: g.prefix, + PrefixLower: strings.ToLower(g.prefix), + Operations: ops, + } +} + +// GenerateReceiver generates the receiver interface and handler functions. +func (g *ReceiverGenerator) GenerateReceiver(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + + if err := g.tmpl.ExecuteTemplate(&buf, "receiver", g.templateData(ops)); err != nil { + return "", fmt.Errorf("generating receiver code: %w", err) + } + + return buf.String(), nil +} + +// GenerateParamTypes generates the parameter struct types. +func (g *ReceiverGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateErrors generates error types (shared with server). +func (g *ReceiverGenerator) GenerateErrors() (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "errors", nil); err != nil { + return "", err + } + return buf.String(), nil +} diff --git a/experimental/internal/codegen/schema.go b/experimental/internal/codegen/schema.go new file mode 100644 index 0000000000..bb0770bb65 --- /dev/null +++ b/experimental/internal/codegen/schema.go @@ -0,0 +1,117 @@ +package codegen + +import ( + "strings" + + "github.com/pb33f/libopenapi/datamodel/high/base" +) + +// SchemaPath represents the location of a schema in the OpenAPI document. +// Used for deriving type names and disambiguating collisions. +// Example: ["components", "schemas", "Pet", "properties", "address"] +type SchemaPath []string + +// String returns the path as a JSON pointer-style string. +func (p SchemaPath) String() string { + return "#/" + strings.Join(p, "/") +} + +// Append returns a new SchemaPath with the given elements appended. +// This creates a fresh slice to avoid aliasing issues with append. +func (p SchemaPath) Append(elements ...string) SchemaPath { + result := make(SchemaPath, len(p)+len(elements)) + copy(result, p) + copy(result[len(p):], elements) + return result +} + +// ContainsProperties returns true if this path contains "properties" anywhere. +// This indicates it's an inline property schema rather than a component schema. +func (p SchemaPath) ContainsProperties() bool { + for _, element := range p { + if element == "properties" { + return true + } + } + return false +} + +// SchemaDescriptor represents a schema found during the first pass through the spec. +type SchemaDescriptor struct { + // Path is where this schema appears in the document + Path SchemaPath + + // Ref is the $ref string if this is a reference (e.g., "#/components/schemas/Pet") + // Empty if this is an inline schema definition + Ref string + + // Schema is the underlying schema from libopenapi + // nil for unresolved external references + Schema *base.Schema + + // Parent points to the containing schema (nil for top-level schemas) + Parent *SchemaDescriptor + + // StableName is the deterministic Go type name derived from the full path. + // This name is stable across spec changes and should be used for type definitions. + // Example: #/components/schemas/Cat -> CatSchemaComponent + StableName string + + // ShortName is a friendly alias that may change due to deduplication. + // Generated as a type alias pointing to StableName. + ShortName string + + // OperationID is the operationId from the path operation, if this schema + // comes from a path's request body or response. Used for friendlier naming. + OperationID string + + // ContentType is the media type (e.g., "application/json") if this schema + // comes from a request body or response content. Used for naming. + ContentType string + + // Extensions holds parsed x- extension values for this schema. + // These control code generation behavior (type overrides, field names, etc.) + Extensions *Extensions + + // Recursive structure: + Properties map[string]*SchemaDescriptor + Items *SchemaDescriptor + AllOf []*SchemaDescriptor + AnyOf []*SchemaDescriptor + OneOf []*SchemaDescriptor + AdditionalProps *SchemaDescriptor +} + +// IsReference returns true if this schema is a $ref to another schema +func (d *SchemaDescriptor) IsReference() bool { + return d.Ref != "" +} + +// IsExternalReference returns true if this is a reference to an external file. +// External refs have the format: file.yaml#/path/to/schema +func (d *SchemaDescriptor) IsExternalReference() bool { + if d.Ref == "" { + return false + } + // External refs contain # but don't start with it + return !strings.HasPrefix(d.Ref, "#") && strings.Contains(d.Ref, "#") +} + +// ParseExternalRef splits an external reference into its file path and internal path. +// For "common/api.yaml#/components/schemas/Pet", returns ("common/api.yaml", "#/components/schemas/Pet"). +// Returns empty strings if not an external ref. +func (d *SchemaDescriptor) ParseExternalRef() (filePath, internalPath string) { + if !d.IsExternalReference() { + return "", "" + } + parts := strings.SplitN(d.Ref, "#", 2) + if len(parts) != 2 { + return "", "" + } + return parts[0], "#" + parts[1] +} + +// IsComponentSchema returns true if this schema is defined in #/components/schemas +func (d *SchemaDescriptor) IsComponentSchema() bool { + return len(d.Path) >= 2 && d.Path[0] == "components" && d.Path[1] == "schemas" +} diff --git a/experimental/internal/codegen/schemanames.go b/experimental/internal/codegen/schemanames.go new file mode 100644 index 0000000000..c41e8b6cef --- /dev/null +++ b/experimental/internal/codegen/schemanames.go @@ -0,0 +1,812 @@ +package codegen + +import ( + "fmt" + "strings" +) + +// SchemaContext identifies what kind of schema this is based on its location. +type SchemaContext int + +const ( + ContextUnknown SchemaContext = iota + ContextComponentSchema + ContextParameter + ContextRequestBody + ContextResponse + ContextHeader + ContextCallback + ContextWebhook + ContextProperty + ContextItems + ContextAllOf + ContextAnyOf + ContextOneOf + ContextAdditionalProperties +) + +// ComputeSchemaNames assigns StableName and ShortName to each schema descriptor. +// StableName is deterministic from the path; ShortName is a friendly alias. +// If a schema has a TypeNameOverride extension, that takes precedence over computed names. +func ComputeSchemaNames(schemas []*SchemaDescriptor, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) { + // First: compute stable names from full paths + for _, s := range schemas { + // Check for TypeNameOverride extension + if s.Extensions != nil && s.Extensions.TypeNameOverride != "" { + s.StableName = s.Extensions.TypeNameOverride + } else { + s.StableName = computeStableName(s.Path, converter) + } + } + + // Second: generate candidate short names + candidates := make(map[*SchemaDescriptor]string) + for _, s := range schemas { + // TypeNameOverride also applies to short names + if s.Extensions != nil && s.Extensions.TypeNameOverride != "" { + candidates[s] = s.Extensions.TypeNameOverride + } else { + candidates[s] = generateCandidateName(s, converter, contentTypeNamer) + } + } + + // Third: detect collisions and resolve them for short names + resolveCollisions(schemas, candidates, converter) + + // Assign final short names + for _, s := range schemas { + s.ShortName = candidates[s] + } +} + +// computeStableName generates a deterministic type name from the full path. +// The format is: {meaningful_names}{reversed_context_suffix} +// Example: #/components/schemas/Cat -> CatSchemaComponent +func computeStableName(path SchemaPath, converter *NameConverter) string { + if len(path) == 0 { + return "Schema" + } + + // Separate path into name parts and context parts + var nameParts []string + var contextParts []string + + for i := 0; i < len(path); i++ { + part := path[i] + // Strip leading slash from API paths (e.g., "/pets" -> "pets") + part = strings.TrimPrefix(part, "/") + if part == "" { + continue + } + if isContextKeyword(part) { + contextParts = append(contextParts, part) + } else { + nameParts = append(nameParts, part) + } + } + + // Build the name: names first, then reversed context as suffix + var result strings.Builder + + // Add name parts + // First part uses ToTypeName (adds numeric prefix if needed) + // Subsequent parts use ToTypeNamePart (no numeric prefix since they're not at the start) + for i, name := range nameParts { + if i == 0 { + result.WriteString(converter.ToTypeName(name)) + } else { + result.WriteString(converter.ToTypeNamePart(name)) + } + } + + // Add reversed context as suffix (singularized) + for i := len(contextParts) - 1; i >= 0; i-- { + suffix := contextToSuffix(contextParts[i]) + result.WriteString(suffix) + } + + name := result.String() + if name == "" { + return "Schema" + } + return name +} + +// isContextKeyword returns true if the path segment is a structural keyword +// rather than a user-defined name. +func isContextKeyword(s string) bool { + switch s { + case "components", "schemas", "parameters", "responses", "requestBodies", + "headers", "callbacks", "paths", "webhooks", + "properties", "items", "additionalProperties", + "allOf", "anyOf", "oneOf", "not", + "prefixItems", "contains", "if", "then", "else", + "dependentSchemas", "patternProperties", "propertyNames", + "unevaluatedItems", "unevaluatedProperties", + "content", "schema", "requestBody": + return true + default: + return false + } +} + +// contextToSuffix converts a context keyword to its singular suffix form. +func contextToSuffix(context string) string { + switch context { + case "components": + return "Component" + case "schemas": + return "Schema" + case "parameters": + return "Parameter" + case "responses": + return "Response" + case "requestBodies", "requestBody": + return "Request" + case "headers": + return "Header" + case "callbacks": + return "Callback" + case "paths": + return "Path" + case "webhooks": + return "Webhook" + case "properties": + return "Property" + case "items": + return "Item" + case "additionalProperties": + return "Value" + case "allOf": + return "AllOf" + case "anyOf": + return "AnyOf" + case "oneOf": + return "OneOf" + case "not": + return "Not" + case "prefixItems": + return "PrefixItem" + case "contains": + return "Contains" + case "if": + return "If" + case "then": + return "Then" + case "else": + return "Else" + case "content": + return "Content" + case "schema": + return "" // Skip redundant "Schema" suffix from content/schema + default: + return "" + } +} + +// generateCandidateName creates a candidate short name based on the schema's path. +func generateCandidateName(s *SchemaDescriptor, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { + path := s.Path + if len(path) == 0 { + return "Schema" + } + + ctx, parts := parsePathContext(path) + + switch ctx { + case ContextComponentSchema: + // #/components/schemas/Cat -> "Cat" + // #/components/schemas/Cat/properties/name -> "CatName" + return buildComponentSchemaName(parts, converter) + + case ContextParameter: + // Always suffix with Parameter + return buildParameterName(parts, converter) + + case ContextRequestBody: + // Use operationId if available for nicer names, but only for the direct request body schema + // (not nested items, properties, etc.) + if s.OperationID != "" && isDirectBodySchema(path) { + return buildOperationRequestName(s.OperationID, s.ContentType, converter, contentTypeNamer) + } + return buildRequestBodyName(parts, converter) + + case ContextResponse: + // Use operationId if available for nicer names, but only for the direct response schema + // (not nested items, properties, etc.) + if s.OperationID != "" && isDirectBodySchema(path) { + // Extract status code from path + statusCode := extractStatusCode(parts) + return buildOperationResponseName(s.OperationID, statusCode, s.ContentType, converter, contentTypeNamer) + } + return buildResponseName(parts, converter) + + case ContextHeader: + return buildHeaderName(parts, converter) + + case ContextCallback: + return buildCallbackName(parts, converter) + + case ContextWebhook: + return buildWebhookName(parts, converter) + + default: + // Fallback: join all meaningful parts + return buildFallbackName(path, converter) + } +} + +// parsePathContext determines the schema context and extracts relevant path parts. +func parsePathContext(path SchemaPath) (SchemaContext, []string) { + if len(path) == 0 { + return ContextUnknown, nil + } + + switch path[0] { + case "components": + if len(path) >= 3 && path[1] == "schemas" { + return ContextComponentSchema, path[2:] + } + if len(path) >= 3 && path[1] == "parameters" { + return ContextParameter, path[2:] + } + if len(path) >= 3 && path[1] == "requestBodies" { + return ContextRequestBody, path[2:] + } + if len(path) >= 3 && path[1] == "responses" { + return ContextResponse, path[2:] + } + if len(path) >= 3 && path[1] == "headers" { + return ContextHeader, path[2:] + } + if len(path) >= 3 && path[1] == "callbacks" { + return ContextCallback, path[2:] + } + + case "paths": + // paths/{path}/{method}/... + if len(path) >= 3 { + remaining := path[3:] // skip paths, {path}, {method} + return detectPathsContext(remaining), path[1:] // include path and method + } + + case "webhooks": + return ContextWebhook, path[1:] + } + + return ContextUnknown, path +} + +// detectPathsContext determines context from within a path item. +func detectPathsContext(remaining SchemaPath) SchemaContext { + if len(remaining) == 0 { + return ContextUnknown + } + + switch remaining[0] { + case "parameters": + return ContextParameter + case "requestBody": + return ContextRequestBody + case "responses": + return ContextResponse + case "callbacks": + return ContextCallback + } + + return ContextUnknown +} + +// buildComponentSchemaName builds a name for a component schema. +// e.g., ["Cat"] -> "Cat", ["Cat", "properties", "name"] -> "CatName" +func buildComponentSchemaName(parts []string, converter *NameConverter) string { + if len(parts) == 0 { + return "Schema" + } + + var nameParts []string + nameParts = append(nameParts, parts[0]) // schema name + + // Track trailing structural elements (only add suffix if they're at the end) + trailingSuffix := "" + + // Process nested parts + for i := 1; i < len(parts); i++ { + part := parts[i] + switch part { + case "properties": + // Skip, but next part (property name) will be added + // Clear trailing suffix since we're going deeper + trailingSuffix = "" + continue + case "items": + // Accumulate Item suffix (for nested arrays) + trailingSuffix += "Item" + continue + case "additionalProperties": + // Set Value suffix + trailingSuffix = "Value" + continue + case "allOf", "anyOf", "oneOf": + // Include the composition type and index + trailingSuffix = "" // Clear since we're adding meaningful content + if i+1 < len(parts) { + nameParts = append(nameParts, part+parts[i+1]) + i++ // Skip the index + } else { + nameParts = append(nameParts, part) + } + case "not", "prefixItems", "contains", "if", "then", "else": + // Include these structural keywords + trailingSuffix = "" + nameParts = append(nameParts, part) + default: + // Include meaningful parts (property names, indices) + // Clear trailing suffix since we have a meaningful name part + trailingSuffix = "" + nameParts = append(nameParts, part) + } + } + + name := converter.ToTypeName(strings.Join(nameParts, "_")) + + // Add trailing structural suffix if still present + if trailingSuffix != "" { + name += trailingSuffix + } + + return name +} + +// buildParameterName builds a name for a parameter schema. +func buildParameterName(parts []string, converter *NameConverter) string { + // parts could be: + // - from components/parameters: [paramName, "schema"] + // - from paths: [path, method, "parameters", index, "schema"] + + var baseName string + if len(parts) >= 2 && parts[0] != "" { + // Try to extract operation-style name + baseName = buildOperationName(parts, converter) + } + if baseName == "" && len(parts) > 0 { + baseName = converter.ToTypeName(parts[0]) + } + if baseName == "" { + baseName = "Param" + } + + // Always add Parameter suffix + if !strings.HasSuffix(baseName, "Parameter") { + baseName += "Parameter" + } + return baseName +} + +// buildRequestBodyName builds a name for a request body schema. +func buildRequestBodyName(parts []string, converter *NameConverter) string { + var baseName string + if len(parts) >= 2 { + baseName = buildOperationName(parts, converter) + } + if baseName == "" && len(parts) > 0 { + baseName = converter.ToTypeName(parts[0]) + } + if baseName == "" { + baseName = "Request" + } + + // Always add Request suffix + if !strings.HasSuffix(baseName, "Request") { + baseName += "Request" + } + return baseName +} + +// buildResponseName builds a name for a response schema. +func buildResponseName(parts []string, converter *NameConverter) string { + var baseName string + var statusCode string + + if len(parts) >= 4 { + // paths: [path, method, "responses", code, ...] + baseName = buildOperationName(parts[:2], converter) + // Find status code + for i, p := range parts { + if p == "responses" && i+1 < len(parts) { + statusCode = parts[i+1] + break + } + } + } + if baseName == "" && len(parts) > 0 { + baseName = converter.ToTypeName(parts[0]) + } + if baseName == "" { + baseName = "Response" + } + + // Add status code if present + if statusCode != "" && statusCode != "default" { + baseName += statusCode + } + + // Always add Response suffix + if !strings.HasSuffix(baseName, "Response") { + baseName += "Response" + } + return baseName +} + +// buildHeaderName builds a name for a header schema. +func buildHeaderName(parts []string, converter *NameConverter) string { + if len(parts) == 0 { + return "Header" + } + baseName := converter.ToTypeName(parts[0]) + if !strings.HasSuffix(baseName, "Header") { + baseName += "Header" + } + return baseName +} + +// buildCallbackName builds a name for a callback schema. +func buildCallbackName(parts []string, converter *NameConverter) string { + if len(parts) == 0 { + return "Callback" + } + return converter.ToTypeName(parts[0]) + "Callback" +} + +// buildWebhookName builds a name for a webhook schema. +func buildWebhookName(parts []string, converter *NameConverter) string { + if len(parts) == 0 { + return "Webhook" + } + return converter.ToTypeName(parts[0]) + "Webhook" +} + +// buildOperationName builds a name from path and method. +// e.g., ["/pets", "get"] -> "GetPets" +func buildOperationName(parts []string, converter *NameConverter) string { + if len(parts) < 2 { + return "" + } + + pathStr := parts[0] + method := parts[1] + + // Convert method to title case + methodName := converter.ToTypeName(method) + + // Convert path to name parts + // /pets/{petId}/toys -> PetsPetIdToys + pathName := pathToName(pathStr, converter) + + return methodName + pathName +} + +// pathToName converts an API path to a name component. +// e.g., "/pets/{petId}" -> "PetsPetId" +func pathToName(path string, converter *NameConverter) string { + // Remove leading slash + path = strings.TrimPrefix(path, "/") + + // Split by slash + segments := strings.Split(path, "/") + + var parts []string + for _, seg := range segments { + if seg == "" { + continue + } + // Remove braces from path parameters + seg = strings.TrimPrefix(seg, "{") + seg = strings.TrimSuffix(seg, "}") + parts = append(parts, seg) + } + + return converter.ToTypeName(strings.Join(parts, "_")) +} + +// buildFallbackName creates a name from the full path as a last resort. +func buildFallbackName(path SchemaPath, converter *NameConverter) string { + var parts []string + for _, p := range path { + // Skip common structural elements + switch p { + case "components", "schemas", "paths", "properties", + "items", "schema", "content", "application/json": + continue + default: + parts = append(parts, p) + } + } + + if len(parts) == 0 { + return "Schema" + } + + return converter.ToTypeName(strings.Join(parts, "_")) +} + +// schemaContextSuffix maps a SchemaContext to a disambiguation suffix. +func schemaContextSuffix(ctx SchemaContext) string { + switch ctx { + case ContextComponentSchema: + return "Schema" + case ContextParameter: + return "Parameter" + case ContextRequestBody: + return "Request" + case ContextResponse: + return "Response" + case ContextHeader: + return "Header" + case ContextCallback: + return "Callback" + case ContextWebhook: + return "Webhook" + default: + return "" + } +} + +// resolveCollisions detects name collisions and makes them unique. +// Reference schemas are excluded from collision detection because they don't +// generate types — their names are only used for type resolution lookups. +// +// Resolution proceeds in phases: +// 1. Context suffix: append a suffix derived from the schema's location +// (e.g. "Request", "Response"). If exactly one collider lives under +// components/schemas it keeps the bare name. +// 2. Existing disambiguateName logic (content type, status code, composition). +// 3. Numeric fallback as a last resort. +func resolveCollisions(schemas []*SchemaDescriptor, candidates map[*SchemaDescriptor]string, converter *NameConverter) { + // Filter out reference schemas — they don't generate types so their + // short names can safely shadow non-ref names without causing a collision. + var nonRefSchemas []*SchemaDescriptor + for _, s := range schemas { + if s.Ref == "" { + nonRefSchemas = append(nonRefSchemas, s) + } + } + + maxIterations := 10 // Prevent infinite loops + + for iteration := range maxIterations { + // Group non-ref schemas by candidate name + byName := make(map[string][]*SchemaDescriptor) + for _, s := range nonRefSchemas { + name := candidates[s] + byName[name] = append(byName[name], s) + } + + // Check if there are any collisions + hasCollisions := false + for _, group := range byName { + if len(group) > 1 { + hasCollisions = true + break + } + } + + if !hasCollisions { + return // All names are unique + } + + // Resolve collisions + for _, group := range byName { + if len(group) <= 1 { + continue // No collision + } + + // On last iteration, just add numeric suffixes + if iteration == maxIterations-1 { + for i, s := range group { + candidates[s] = fmt.Sprintf("%s%d", candidates[s], i+1) + } + continue + } + + // First iteration: try context suffix disambiguation + if iteration == 0 { + resolveWithContextSuffix(group, candidates) + continue + } + + // Subsequent iterations: existing disambiguateName logic + for i, s := range group { + newName := disambiguateName(s, candidates[s], i, converter) + candidates[s] = newName + } + } + } +} + +// resolveWithContextSuffix attempts to disambiguate colliding schemas by +// appending a suffix derived from their path context (e.g. "Request", +// "Response"). If exactly one member is a component schema, it keeps the +// bare name and only the others are suffixed. +func resolveWithContextSuffix(group []*SchemaDescriptor, candidates map[*SchemaDescriptor]string) { + // Count how many are from components/schemas + var componentSchemaCount int + for _, s := range group { + ctx, _ := parsePathContext(s.Path) + if ctx == ContextComponentSchema { + componentSchemaCount++ + } + } + + // If exactly one is from components/schemas, it is "privileged" and keeps + // the bare name. + privileged := componentSchemaCount == 1 + + for _, s := range group { + ctx, _ := parsePathContext(s.Path) + + // Privileged component schema keeps the bare name + if privileged && ctx == ContextComponentSchema { + continue + } + + suffix := schemaContextSuffix(ctx) + if suffix != "" { + name := candidates[s] + if !strings.HasSuffix(name, suffix) { + candidates[s] = name + suffix + } + } + // If suffix is empty (unknown context), leave unchanged for later + // iterations to handle via disambiguateName. + } +} + +// disambiguateName adds more context to make a name unique. +func disambiguateName(s *SchemaDescriptor, currentName string, index int, converter *NameConverter) string { + path := s.Path + + // Try to add more path context based on what's in the path + // but not already in the name + + // Check for content type differentiation + for i, part := range path { + if part == "content" && i+1 < len(path) { + contentType := path[i+1] + var suffix string + switch { + case strings.Contains(contentType, "json"): + suffix = "JSON" + case strings.Contains(contentType, "xml"): + suffix = "XML" + case strings.Contains(contentType, "form"): + suffix = "Form" + case strings.Contains(contentType, "text"): + suffix = "Text" + case strings.Contains(contentType, "binary"): + suffix = "Binary" + default: + suffix = converter.ToTypeName(strings.ReplaceAll(contentType, "/", "_")) + } + // Use Contains since the suffix might be embedded before "Response" or "Request" + if !strings.Contains(currentName, suffix) { + return currentName + suffix + } + } + } + + // Check for status code differentiation (for responses) + for i, part := range path { + if part == "responses" && i+1 < len(path) { + code := path[i+1] + if !strings.Contains(currentName, code) { + return currentName + code + } + } + } + + // Check for parameter index differentiation + for i, part := range path { + if part == "parameters" && i+1 < len(path) { + idx := path[i+1] + if !strings.HasSuffix(currentName, idx) { + return currentName + idx + } + } + } + + // Check for composition type differentiation + for i := len(path) - 1; i >= 0; i-- { + part := path[i] + switch part { + case "allOf", "anyOf", "oneOf": + suffix := converter.ToTypeName(part) + if i+1 < len(path) { + suffix += path[i+1] // Add index + } + if !strings.Contains(currentName, suffix) { + return currentName + suffix + } + } + } + + // Last resort: use numeric suffix + return fmt.Sprintf("%s%d", currentName, index+1) +} + +// buildOperationRequestName builds a name for a request body using the operationId. +// e.g., operationId="addPet" -> "AddPetJSONRequest" +func buildOperationRequestName(operationID, contentType string, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { + baseName := converter.ToTypeName(operationID) + + // Add content type short name if available + if contentType != "" && contentTypeNamer != nil { + baseName += contentTypeNamer.ShortName(contentType) + } + + return baseName + "Request" +} + +// buildOperationResponseName builds a name for a response using the operationId. +// e.g., operationId="findPets", statusCode="200" -> "FindPetsJSONResponse" +// e.g., operationId="findPets", statusCode="404" -> "FindPets404JSONResponse" +// e.g., operationId="findPets", statusCode="default" -> "FindPetsDefaultJSONResponse" +func buildOperationResponseName(operationID, statusCode, contentType string, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { + baseName := converter.ToTypeName(operationID) + + // Add status code, skipping only for 200 (the common success case) + if statusCode != "" && statusCode != "200" { + if statusCode == "default" { + baseName += "Default" + } else { + baseName += statusCode + } + } + + // Add content type short name if available + if contentType != "" && contentTypeNamer != nil { + baseName += contentTypeNamer.ShortName(contentType) + } + + return baseName + "Response" +} + +// extractStatusCode extracts the HTTP status code from path parts. +// Looks for "responses" followed by the status code. +func extractStatusCode(parts []string) string { + for i, p := range parts { + if p == "responses" && i+1 < len(parts) { + return parts[i+1] + } + } + return "" +} + +// isDirectBodySchema returns true if the schema path represents the direct +// schema of a request body or response (i.e., content/{type}/schema), +// not a nested schema (items, properties, allOf members, etc.). +func isDirectBodySchema(path SchemaPath) bool { + // Find the position of "schema" after "content" + schemaIdx := -1 + for i := len(path) - 1; i >= 0; i-- { + if path[i] == "schema" { + schemaIdx = i + break + } + } + if schemaIdx == -1 { + return false + } + + // Check that "schema" is directly after a content type (content/{type}/schema) + // and there are no structural elements after it + if schemaIdx < 2 { + return false + } + if path[schemaIdx-2] != "content" { + return false + } + + // If schema is at the end of the path, it's a direct body schema + return schemaIdx == len(path)-1 +} diff --git a/experimental/internal/codegen/servergen.go b/experimental/internal/codegen/servergen.go new file mode 100644 index 0000000000..86177c4167 --- /dev/null +++ b/experimental/internal/codegen/servergen.go @@ -0,0 +1,180 @@ +package codegen + +import ( + "bytes" + "fmt" + "text/template" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +// ServerGenerator generates server code from operation descriptors. +type ServerGenerator struct { + tmpl *template.Template + serverType string +} + +// NewServerGenerator creates a new server generator for the specified server type. +func NewServerGenerator(serverType string) (*ServerGenerator, error) { + if serverType == "" { + // No server generation requested + return &ServerGenerator{serverType: ""}, nil + } + + tmpl := template.New("server").Funcs(templates.Funcs()) + + // Get templates for the specified server type + serverTemplates, err := getServerTemplates(serverType) + if err != nil { + return nil, err + } + + // Parse server-specific templates + for _, st := range serverTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + st.Template) + if err != nil { + return nil, fmt.Errorf("failed to read template %s: %w", st.Template, err) + } + _, err = tmpl.New(st.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse template %s: %w", st.Template, err) + } + } + + // Parse shared templates + for _, st := range templates.SharedServerTemplates { + content, err := templates.TemplateFS.ReadFile("files/" + st.Template) + if err != nil { + return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) + } + _, err = tmpl.New(st.Name).Parse(string(content)) + if err != nil { + return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) + } + } + + return &ServerGenerator{tmpl: tmpl, serverType: serverType}, nil +} + +// getServerTemplates returns the templates for the specified server type. +func getServerTemplates(serverType string) (map[string]templates.ServerTemplate, error) { + switch serverType { + case ServerTypeStdHTTP: + return templates.StdHTTPServerTemplates, nil + case ServerTypeChi: + return templates.ChiServerTemplates, nil + case ServerTypeEcho: + return templates.EchoServerTemplates, nil + case ServerTypeEchoV4: + return templates.EchoV4ServerTemplates, nil + case ServerTypeGin: + return templates.GinServerTemplates, nil + case ServerTypeGorilla: + return templates.GorillaServerTemplates, nil + case ServerTypeFiber: + return templates.FiberServerTemplates, nil + case ServerTypeIris: + return templates.IrisServerTemplates, nil + default: + return nil, fmt.Errorf("unsupported server type: %q (supported: %q, %q, %q, %q, %q, %q, %q, %q)", + serverType, + ServerTypeStdHTTP, ServerTypeChi, ServerTypeEcho, ServerTypeEchoV4, ServerTypeGin, + ServerTypeGorilla, ServerTypeFiber, ServerTypeIris) + } +} + +// GenerateInterface generates the ServerInterface. +func (g *ServerGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "interface", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateHandler generates the HTTP handler and routing code. +func (g *ServerGenerator) GenerateHandler(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "handler", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateWrapper generates the ServerInterfaceWrapper. +func (g *ServerGenerator) GenerateWrapper(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "wrapper", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateErrors generates the error types. +func (g *ServerGenerator) GenerateErrors() (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "errors", nil); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateParamTypes generates the parameter struct types. +func (g *ServerGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { + var buf bytes.Buffer + if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { + return "", err + } + return buf.String(), nil +} + +// GenerateServer generates all server code components. +// Returns empty string if no server type was configured. +func (g *ServerGenerator) GenerateServer(ops []*OperationDescriptor) (string, error) { + if g.serverType == "" || g.tmpl == nil { + return "", nil + } + + var buf bytes.Buffer + + // Generate interface + iface, err := g.GenerateInterface(ops) + if err != nil { + return "", err + } + buf.WriteString(iface) + buf.WriteString("\n") + + // Generate param types + paramTypes, err := g.GenerateParamTypes(ops) + if err != nil { + return "", err + } + buf.WriteString(paramTypes) + buf.WriteString("\n") + + // Generate wrapper + wrapper, err := g.GenerateWrapper(ops) + if err != nil { + return "", err + } + buf.WriteString(wrapper) + buf.WriteString("\n") + + // Generate handler + handler, err := g.GenerateHandler(ops) + if err != nil { + return "", err + } + buf.WriteString(handler) + buf.WriteString("\n") + + // Generate errors + errors, err := g.GenerateErrors() + if err != nil { + return "", err + } + buf.WriteString(errors) + + return buf.String(), nil +} diff --git a/experimental/internal/codegen/skip_external_ref_test.go b/experimental/internal/codegen/skip_external_ref_test.go new file mode 100644 index 0000000000..6983852a73 --- /dev/null +++ b/experimental/internal/codegen/skip_external_ref_test.go @@ -0,0 +1,68 @@ +package codegen + +import ( + "os" + "strings" + "testing" + + "github.com/pb33f/libopenapi" + "github.com/pb33f/libopenapi/datamodel" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestSkipExternalRefResolution verifies that we can parse a spec containing +// external $ref references without resolving them, and still generate correct +// code using import mappings. This uses libopenapi's SkipExternalRefResolution +// flag (added in v0.33.4, pb33f/libopenapi#519). +func TestSkipExternalRefResolution(t *testing.T) { + specData, err := os.ReadFile("test/external_ref/spec.yaml") + require.NoError(t, err) + + // Parse WITHOUT BasePath or AllowFileReferences — the external spec files + // won't be read. Instead, we rely on SkipExternalRefResolution to leave + // external $refs unresolved while still building an iterable model. + docConfig := datamodel.NewDocumentConfiguration() + docConfig.SkipExternalRefResolution = true + + doc, err := libopenapi.NewDocumentWithConfiguration(specData, docConfig) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "externalref", + ImportMapping: map[string]string{ + "./packagea/spec.yaml": "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea", + "./packageb/spec.yaml": "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb", + }, + } + + code, err := Generate(doc, nil, cfg) + require.NoError(t, err) + + // The generated code should contain the Container struct with external type references + assert.Contains(t, code, "type Container struct") + assert.Contains(t, code, "ObjectA") + assert.Contains(t, code, "ObjectB") + + // Should reference the external packages via hashed aliases + assert.Contains(t, code, "ext_95d82e90") + assert.Contains(t, code, "ext_a5fddf6c") + + // Should contain the import declarations + assert.Contains(t, code, `"github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea"`) + assert.Contains(t, code, `"github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb"`) + + // Should NOT contain "any" as a fallback type for the external refs + // (which would indicate the refs weren't properly detected) + lines := strings.Split(code, "\n") + for _, line := range lines { + if strings.Contains(line, "ObjectA") && strings.Contains(line, "any") { + t.Errorf("ObjectA resolved to 'any' instead of external type: %s", line) + } + if strings.Contains(line, "ObjectB") && strings.Contains(line, "any") { + t.Errorf("ObjectB resolved to 'any' instead of external type: %s", line) + } + } + + t.Logf("Generated code:\n%s", code) +} diff --git a/experimental/internal/codegen/structtags.go b/experimental/internal/codegen/structtags.go new file mode 100644 index 0000000000..36279956b7 --- /dev/null +++ b/experimental/internal/codegen/structtags.go @@ -0,0 +1,172 @@ +package codegen + +import ( + "bytes" + "sort" + "strings" + "text/template" +) + +// StructTagInfo contains the data available to struct tag templates. +type StructTagInfo struct { + // FieldName is the JSON/YAML field name (from the OpenAPI property name) + FieldName string + // GoFieldName is the Go struct field name + GoFieldName string + // IsOptional is true if the field is optional (not required) + IsOptional bool + // IsNullable is true if the field can be null + IsNullable bool + // IsPointer is true if the Go type is a pointer + IsPointer bool + // OmitEmpty is true if the omitempty tag option should be used + // (derived from IsOptional but can be overridden via extensions) + OmitEmpty bool + // OmitZero is true if the omitzero tag option should be used (Go 1.24+) + OmitZero bool + // JSONIgnore is true if the field should be excluded from JSON (json:"-") + JSONIgnore bool +} + +// StructTagTemplate defines a single struct tag with a name and template. +type StructTagTemplate struct { + // Name is the tag name (e.g., "json", "yaml", "form") + Name string `yaml:"name"` + // Template is a Go text/template that produces the tag value. + // Available fields: .FieldName, .GoFieldName, .IsOptional, .IsNullable, .IsPointer + // Example: `{{ .FieldName }}{{if .IsOptional}},omitempty{{end}}` + Template string `yaml:"template"` +} + +// StructTagsConfig configures struct tag generation. +type StructTagsConfig struct { + // Tags is the list of tags to generate for struct fields. + // Order is preserved in the generated output. + Tags []StructTagTemplate `yaml:"tags,omitempty"` +} + +// DefaultStructTagsConfig returns the default struct tag configuration. +// By default, json and form tags are generated. +func DefaultStructTagsConfig() StructTagsConfig { + return StructTagsConfig{ + Tags: []StructTagTemplate{ + { + Name: "json", + Template: `{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{if .OmitZero}},omitzero{{end}}{{end}}`, + }, + { + Name: "form", + Template: `{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{end}}`, + }, + }, + } +} + +// Merge merges user config on top of this config. +// If user specifies any tags, they completely replace the defaults. +func (c StructTagsConfig) Merge(other StructTagsConfig) StructTagsConfig { + if len(other.Tags) > 0 { + return other + } + return c +} + +// StructTagGenerator generates struct tags from templates. +type StructTagGenerator struct { + templates []*tagTemplate +} + +type tagTemplate struct { + name string + tmpl *template.Template +} + +// NewStructTagGenerator creates a generator from the configuration. +// Invalid templates are silently skipped. +func NewStructTagGenerator(config StructTagsConfig) *StructTagGenerator { + g := &StructTagGenerator{ + templates: make([]*tagTemplate, 0, len(config.Tags)), + } + + for _, tag := range config.Tags { + tmpl, err := template.New(tag.Name).Parse(tag.Template) + if err != nil { + // Skip invalid templates + continue + } + g.templates = append(g.templates, &tagTemplate{ + name: tag.Name, + tmpl: tmpl, + }) + } + + return g +} + +// GenerateTags generates the complete struct tag string for a field. +// Returns a string like `json:"name,omitempty" yaml:"name,omitempty"`. +func (g *StructTagGenerator) GenerateTags(info StructTagInfo) string { + if len(g.templates) == 0 { + return "" + } + + var tags []string + for _, t := range g.templates { + var buf bytes.Buffer + if err := t.tmpl.Execute(&buf, info); err != nil { + // Skip tags that fail to render + continue + } + value := buf.String() + if value != "" { + tags = append(tags, t.name+`:`+`"`+value+`"`) + } + } + + if len(tags) == 0 { + return "" + } + + return "`" + strings.Join(tags, " ") + "`" +} + +// GenerateTagsMap generates tags as a map for cases where we need to add extra tags. +// Returns a map of tag name -> tag value (without quotes). +func (g *StructTagGenerator) GenerateTagsMap(info StructTagInfo) map[string]string { + result := make(map[string]string) + + for _, t := range g.templates { + var buf bytes.Buffer + if err := t.tmpl.Execute(&buf, info); err != nil { + continue + } + value := buf.String() + if value != "" { + result[t.name] = value + } + } + + return result +} + +// FormatTagsMap formats a tag map into a struct tag string. +// Tags are sorted alphabetically by name for deterministic output. +func FormatTagsMap(tags map[string]string) string { + if len(tags) == 0 { + return "" + } + + // Sort tag names for deterministic output + names := make([]string, 0, len(tags)) + for name := range tags { + names = append(names, name) + } + sort.Strings(names) + + var parts []string + for _, name := range names { + parts = append(parts, name+`:`+`"`+tags[name]+`"`) + } + + return "`" + strings.Join(parts, " ") + "`" +} diff --git a/experimental/internal/codegen/templates/embed.go b/experimental/internal/codegen/templates/embed.go new file mode 100644 index 0000000000..ed91bb95e7 --- /dev/null +++ b/experimental/internal/codegen/templates/embed.go @@ -0,0 +1,9 @@ +package templates + +import "embed" + +// TemplateFS contains all embedded template files. +// The files/* pattern recursively includes all files in subdirectories. +// +//go:embed files/* +var TemplateFS embed.FS diff --git a/experimental/internal/codegen/templates/files/client/base.go.tmpl b/experimental/internal/codegen/templates/files/client/base.go.tmpl new file mode 100644 index 0000000000..96d32997f4 --- /dev/null +++ b/experimental/internal/codegen/templates/files/client/base.go.tmpl @@ -0,0 +1,95 @@ +{{/* Base client template - returns raw *http.Response */}} + +// RequestEditorFn is the function signature for the RequestEditor callback function. +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// HttpRequestDoer 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 + +// NewClient creates a new Client with reasonable defaults. +func NewClient(server string, opts ...ClientOption) (*Client, error) { + client := Client{ + Server: server, + } + 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 + } +} + +// 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 + } +} + +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 +} diff --git a/experimental/internal/codegen/templates/files/client/interface.go.tmpl b/experimental/internal/codegen/templates/files/client/interface.go.tmpl new file mode 100644 index 0000000000..458e4867dc --- /dev/null +++ b/experimental/internal/codegen/templates/files/client/interface.go.tmpl @@ -0,0 +1,17 @@ +{{/* Client interface template */}} + +// ClientInterface is the interface specification for the client. +type ClientInterface interface { +{{- range . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $pathParams := .PathParams }} + // {{ $opid }}{{ if .HasBody }}WithBody{{ end }} makes a {{ .Method }} request to {{ .Path }} + {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ .ParamsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) +{{- range .Bodies }} +{{- if .IsJSON }} + {{ $opid }}{{ .FuncSuffix }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $.ParamsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) +{{- end }} +{{- end }} +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/client/methods.go.tmpl b/experimental/internal/codegen/templates/files/client/methods.go.tmpl new file mode 100644 index 0000000000..a7a6dfd7f1 --- /dev/null +++ b/experimental/internal/codegen/templates/files/client/methods.go.tmpl @@ -0,0 +1,40 @@ +{{/* Client methods template - implements ClientInterface */}} + +{{- range . }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $pathParams := .PathParams }} +{{- $paramsTypeName := .ParamsTypeName }} + +// {{ $opid }}{{ if .HasBody }}WithBody{{ end }} makes a {{ .Method }} request to {{ .Path }} +{{ if .Summary }}// {{ .Summary }}{{ end }} +func (c *Client) {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }}(c.Server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}{{ if .HasBody }}, contentType, body{{ end }}) + 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) +} +{{- range .Bodies }} +{{- if .IsJSON }} + +// {{ $opid }}{{ .FuncSuffix }} makes a {{ $op.Method }} request to {{ $op.Path }} with JSON body +func (c *Client) {{ $opid }}{{ .FuncSuffix }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := New{{ $opid }}Request{{ .FuncSuffix }}(c.Server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, 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) +} +{{- end }} +{{- end }} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl b/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl new file mode 100644 index 0000000000..6461c14de9 --- /dev/null +++ b/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl @@ -0,0 +1,177 @@ +{{/* Request builder functions template */}} + +{{- range . }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $pathParams := .PathParams }} +{{- $paramsTypeName := .ParamsTypeName }} +{{- $queryParams := .QueryParams }} +{{- $headerParams := .HeaderParams }} +{{- $cookieParams := .CookieParams }} + +{{- /* Generate typed body request builders for JSON bodies */ -}} +{{- range .Bodies }} +{{- if .IsJSON }} + +// New{{ $opid }}Request{{ .FuncSuffix }} creates a {{ $op.Method }} request for {{ $op.Path }} with {{ .ContentType }} body +func New{{ $opid }}Request{{ .FuncSuffix }}(server string{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return New{{ $opid }}RequestWithBody(server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, "{{ .ContentType }}", bodyReader) +} +{{- end }} +{{- end }} + +// New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }} creates a {{ .Method }} request for {{ .Path }}{{ if .HasBody }} with any body{{ end }} +func New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }}(server string{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}) (*http.Request, error) { + var err error +{{- range $idx, $param := $pathParams }} + + var pathParam{{ $idx }} string + {{- if .IsPassThrough }} + pathParam{{ $idx }} = {{ .GoVariableName }} + {{- else if .IsJSON }} + var pathParamBuf{{ $idx }} []byte + pathParamBuf{{ $idx }}, err = json.Marshal({{ .GoVariableName }}) + if err != nil { + return nil, err + } + pathParam{{ $idx }} = string(pathParamBuf{{ $idx }}) + {{- else if .IsStyled }} + pathParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationPath, {{ .GoVariableName }}) + if err != nil { + return nil, err + } + {{- end }} +{{- end }} + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("{{ pathFmt .Path }}"{{ range $idx, $_ := $pathParams }}, pathParam{{ $idx }}{{ end }}) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } +{{- if $queryParams }} + + if params != nil { + queryValues := queryURL.Query() +{{- range $idx, $param := $queryParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + {{- if .IsPassThrough }} + queryValues.Add("{{ .Name }}", {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + {{- else if .IsJSON }} + if queryParamBuf, err := json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); err != nil { + return nil, err + } else { + queryValues.Add("{{ .Name }}", string(queryParamBuf)) + } + {{- else if .IsStyled }} + if queryFrag, err := {{ .StyleFunc }}("{{ .Name }}", ParamLocationQuery, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); 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) + } + } + } + {{- end }} + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + queryURL.RawQuery = queryValues.Encode() + } +{{- end }} + + req, err := http.NewRequest("{{ .Method }}", queryURL.String(), {{ if .HasBody }}body{{ else }}nil{{ end }}) + if err != nil { + return nil, err + } + + {{ if .HasBody }}req.Header.Add("Content-Type", contentType){{ end }} +{{- if $headerParams }} + + if params != nil { +{{- range $idx, $param := $headerParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + var headerParam{{ $idx }} string + {{- if .IsPassThrough }} + headerParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} + {{- else if .IsJSON }} + var headerParamBuf{{ $idx }} []byte + headerParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + headerParam{{ $idx }} = string(headerParamBuf{{ $idx }}) + {{- else if .IsStyled }} + headerParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationHeader, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + {{- end }} + req.Header.Set("{{ .Name }}", headerParam{{ $idx }}) + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + } +{{- end }} +{{- if $cookieParams }} + + if params != nil { +{{- range $idx, $param := $cookieParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + var cookieParam{{ $idx }} string + {{- if .IsPassThrough }} + cookieParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} + {{- else if .IsJSON }} + var cookieParamBuf{{ $idx }} []byte + cookieParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + cookieParam{{ $idx }} = url.QueryEscape(string(cookieParamBuf{{ $idx }})) + {{- else if .IsStyled }} + cookieParam{{ $idx }}, err = StyleSimpleParam("{{ .Name }}", ParamLocationCookie, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + {{- end }} + cookie{{ $idx }} := &http.Cookie{ + Name: "{{ .Name }}", + Value: cookieParam{{ $idx }}, + } + req.AddCookie(cookie{{ $idx }}) + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + } +{{- end }} + + return req, nil +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/client/simple.go.tmpl b/experimental/internal/codegen/templates/files/client/simple.go.tmpl new file mode 100644 index 0000000000..988cf73182 --- /dev/null +++ b/experimental/internal/codegen/templates/files/client/simple.go.tmpl @@ -0,0 +1,121 @@ +{{/* SimpleClient template - wraps Client with typed responses for simple operations */}} + +// ClientHttpError represents an HTTP error response from the server. +// The type parameter E is the type of the parsed error body. +type ClientHttpError[E any] struct { + StatusCode int + Body E + RawBody []byte +} + +func (e *ClientHttpError[E]) Error() string { + return fmt.Sprintf("HTTP %d", e.StatusCode) +} + +// SimpleClient wraps Client with typed responses for operations that have +// unambiguous response types. Methods return the success type directly, +// and HTTP errors are returned as *ClientHttpError[E] where E is the error type. +type SimpleClient struct { + *Client +} + +// NewSimpleClient creates a new SimpleClient which wraps a Client. +func NewSimpleClient(server string, opts ...ClientOption) (*SimpleClient, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &SimpleClient{Client: client}, nil +} + +{{- range . }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $pathParams := .PathParams }} +{{- $paramsTypeName := .ParamsTypeName }} + +{{- /* Determine if this operation is "simple" - single success content type, single JSON success response */}} +{{- $simpleOp := isSimpleOperation . }} +{{- if $simpleOp }} +{{- $successResponse := simpleOperationSuccessResponse . }} +{{- $successContent := index $successResponse.Contents 0 }} +{{- $successType := goTypeForContent $successContent }} +{{- $errorResponse := errorResponseForOperation . }} + +// {{ $opid }} makes a {{ .Method }} request to {{ .Path }} and returns the parsed response. +{{ if .Summary }}// {{ .Summary }}{{ end }} +{{- if $errorResponse }} +{{- $errorContent := index $errorResponse.Contents 0 }} +{{- $errorType := goTypeForContent $errorContent }} +// On success, returns the response body. On HTTP error, returns *ClientHttpError[{{ $errorType }}]. +func (c *SimpleClient) {{ $opid }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { + var result {{ $successType }} +{{- if .HasBody }} +{{- $defaultBody := index .Bodies 0 }} + resp, err := c.Client.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, body, reqEditors...) +{{- else }} + resp, err := c.Client.{{ $opid }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, reqEditors...) +{{- end }} + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // Parse error response + var errBody {{ $errorType }} + _ = json.Unmarshal(rawBody, &errBody) // Best effort parse + return result, &ClientHttpError[{{ $errorType }}]{ + StatusCode: resp.StatusCode, + Body: errBody, + RawBody: rawBody, + } +} +{{- else }} +// On success, returns the response body. On HTTP error, returns *ClientHttpError[struct{}]. +func (c *SimpleClient) {{ $opid }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { + var result {{ $successType }} +{{- if .HasBody }} +{{- $defaultBody := index .Bodies 0 }} + resp, err := c.Client.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, body, reqEditors...) +{{- else }} + resp, err := c.Client.{{ $opid }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, reqEditors...) +{{- end }} + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // No typed error response defined + return result, &ClientHttpError[struct{}]{ + StatusCode: resp.StatusCode, + RawBody: rawBody, + } +} +{{- end }} +{{- end }} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/base.go.tmpl b/experimental/internal/codegen/templates/files/initiator/base.go.tmpl new file mode 100644 index 0000000000..99e885136d --- /dev/null +++ b/experimental/internal/codegen/templates/files/initiator/base.go.tmpl @@ -0,0 +1,73 @@ +{{/* Initiator base template - framework-agnostic HTTP client for webhooks/callbacks */}} +{{/* Input: InitiatorTemplateData */}} + +// RequestEditorFn is the function signature for the RequestEditor callback function. +// It may already be defined if client code is also generated; this is a compatible redeclaration. +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// HttpRequestDoer performs HTTP requests. +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// {{ .Prefix }}Initiator sends {{ .PrefixLower }} requests to target URLs. +// Unlike Client, it has no stored base URL — the full target URL is provided per-call. +type {{ .Prefix }}Initiator struct { + // 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 +} + +// {{ .Prefix }}InitiatorOption allows setting custom parameters during construction. +type {{ .Prefix }}InitiatorOption func(*{{ .Prefix }}Initiator) error + +// New{{ .Prefix }}Initiator creates a new {{ .Prefix }}Initiator with reasonable defaults. +func New{{ .Prefix }}Initiator(opts ...{{ .Prefix }}InitiatorOption) (*{{ .Prefix }}Initiator, error) { + initiator := {{ .Prefix }}Initiator{} + for _, o := range opts { + if err := o(&initiator); err != nil { + return nil, err + } + } + if initiator.Client == nil { + initiator.Client = &http.Client{} + } + return &initiator, nil +} + +// With{{ .Prefix }}HTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func With{{ .Prefix }}HTTPClient(doer HttpRequestDoer) {{ .Prefix }}InitiatorOption { + return func(p *{{ .Prefix }}Initiator) error { + p.Client = doer + return nil + } +} + +// With{{ .Prefix }}RequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func With{{ .Prefix }}RequestEditorFn(fn RequestEditorFn) {{ .Prefix }}InitiatorOption { + return func(p *{{ .Prefix }}Initiator) error { + p.RequestEditors = append(p.RequestEditors, fn) + return nil + } +} + +func (p *{{ .Prefix }}Initiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range p.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 +} diff --git a/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl b/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl new file mode 100644 index 0000000000..a6ad431733 --- /dev/null +++ b/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl @@ -0,0 +1,17 @@ +{{/* Initiator interface template */}} +{{/* Input: InitiatorTemplateData */}} + +// {{ .Prefix }}InitiatorInterface is the interface specification for the {{ .PrefixLower }} initiator. +type {{ .Prefix }}InitiatorInterface interface { +{{- range .Operations }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} + // {{ $opid }}{{ if .HasBody }}WithBody{{ end }} sends a {{ .Method }} {{ $.PrefixLower }} request + {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ .ParamsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) +{{- range .Bodies }} +{{- if .IsJSON }} + {{ $opid }}{{ .FuncSuffix }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $.ParamsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) +{{- end }} +{{- end }} +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl b/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl new file mode 100644 index 0000000000..ff079042ed --- /dev/null +++ b/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl @@ -0,0 +1,41 @@ +{{/* Initiator methods template - implements InitiatorInterface */}} +{{/* Input: InitiatorTemplateData */}} + +{{- range .Operations }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $paramsTypeName := .ParamsTypeName }} +{{- $prefix := $.Prefix }} + +// {{ $opid }}{{ if .HasBody }}WithBody{{ end }} sends a {{ .Method }} {{ $.PrefixLower }} request +{{ if .Summary }}// {{ .Summary }}{{ end }} +func (p *{{ $prefix }}Initiator) {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := New{{ $opid }}{{ $.Prefix }}Request{{ if .HasBody }}WithBody{{ end }}(targetURL{{ if $hasParams }}, params{{ end }}{{ if .HasBody }}, contentType, body{{ end }}) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} +{{- range .Bodies }} +{{- if .IsJSON }} + +// {{ $opid }}{{ .FuncSuffix }} sends a {{ $op.Method }} {{ $.PrefixLower }} request with JSON body +func (p *{{ $prefix }}Initiator) {{ $opid }}{{ .FuncSuffix }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }}(targetURL{{ if $hasParams }}, params{{ end }}, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := p.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return p.Client.Do(req) +} +{{- end }} +{{- end }} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl b/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl new file mode 100644 index 0000000000..d651403492 --- /dev/null +++ b/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl @@ -0,0 +1,149 @@ +{{/* Initiator request builder functions template */}} +{{/* Input: InitiatorTemplateData */}} + +{{- range .Operations }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $paramsTypeName := .ParamsTypeName }} +{{- $queryParams := .QueryParams }} +{{- $headerParams := .HeaderParams }} +{{- $cookieParams := .CookieParams }} +{{- $prefix := $.Prefix }} + +{{- /* Generate typed body request builders for JSON bodies */ -}} +{{- range .Bodies }} +{{- if .IsJSON }} + +// New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }} creates a {{ $op.Method }} request for the {{ $.PrefixLower }} with {{ .ContentType }} body +func New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }}(targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return New{{ $opid }}{{ $prefix }}RequestWithBody(targetURL{{ if $hasParams }}, params{{ end }}, "{{ .ContentType }}", bodyReader) +} +{{- end }} +{{- end }} + +// New{{ $opid }}{{ $prefix }}Request{{ if .HasBody }}WithBody{{ end }} creates a {{ .Method }} request for the {{ $.PrefixLower }}{{ if .HasBody }} with any body{{ end }} +func New{{ $opid }}{{ $prefix }}Request{{ if .HasBody }}WithBody{{ end }}(targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}) (*http.Request, error) { + var err error + + parsedURL, err := url.Parse(targetURL) + if err != nil { + return nil, err + } +{{- if $queryParams }} + + if params != nil { + queryValues := parsedURL.Query() +{{- range $idx, $param := $queryParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + {{- if .IsPassThrough }} + queryValues.Add("{{ .Name }}", {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + {{- else if .IsJSON }} + if queryParamBuf, err := json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); err != nil { + return nil, err + } else { + queryValues.Add("{{ .Name }}", string(queryParamBuf)) + } + {{- else if .IsStyled }} + if queryFrag, err := {{ .StyleFunc }}("{{ .Name }}", ParamLocationQuery, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); 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) + } + } + } + {{- end }} + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + parsedURL.RawQuery = queryValues.Encode() + } +{{- end }} + + req, err := http.NewRequest("{{ .Method }}", parsedURL.String(), {{ if .HasBody }}body{{ else }}nil{{ end }}) + if err != nil { + return nil, err + } + + {{ if .HasBody }}req.Header.Add("Content-Type", contentType){{ end }} +{{- if $headerParams }} + + if params != nil { +{{- range $idx, $param := $headerParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + var headerParam{{ $idx }} string + {{- if .IsPassThrough }} + headerParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} + {{- else if .IsJSON }} + var headerParamBuf{{ $idx }} []byte + headerParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + headerParam{{ $idx }} = string(headerParamBuf{{ $idx }}) + {{- else if .IsStyled }} + headerParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationHeader, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + {{- end }} + req.Header.Set("{{ .Name }}", headerParam{{ $idx }}) + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + } +{{- end }} +{{- if $cookieParams }} + + if params != nil { +{{- range $idx, $param := $cookieParams }} + {{- if .HasOptionalPointer }} + if params.{{ .GoName }} != nil { + {{- end }} + var cookieParam{{ $idx }} string + {{- if .IsPassThrough }} + cookieParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} + {{- else if .IsJSON }} + var cookieParamBuf{{ $idx }} []byte + cookieParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + cookieParam{{ $idx }} = url.QueryEscape(string(cookieParamBuf{{ $idx }})) + {{- else if .IsStyled }} + cookieParam{{ $idx }}, err = StyleSimpleParam("{{ .Name }}", ParamLocationCookie, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) + if err != nil { + return nil, err + } + {{- end }} + cookie{{ $idx }} := &http.Cookie{ + Name: "{{ .Name }}", + Value: cookieParam{{ $idx }}, + } + req.AddCookie(cookie{{ $idx }}) + {{- if .HasOptionalPointer }} + } + {{- end }} +{{- end }} + } +{{- end }} + + return req, nil +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl b/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl new file mode 100644 index 0000000000..008d4095ec --- /dev/null +++ b/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl @@ -0,0 +1,121 @@ +{{/* Simple initiator template - wraps Initiator with typed responses for simple operations */}} +{{/* Input: InitiatorTemplateData */}} + +// {{ .Prefix }}HttpError represents an HTTP error response. +// The type parameter E is the type of the parsed error body. +type {{ .Prefix }}HttpError[E any] struct { + StatusCode int + Body E + RawBody []byte +} + +func (e *{{ .Prefix }}HttpError[E]) Error() string { + return fmt.Sprintf("HTTP %d", e.StatusCode) +} + +// Simple{{ .Prefix }}Initiator wraps {{ .Prefix }}Initiator with typed responses for operations that have +// unambiguous response types. Methods return the success type directly, +// and HTTP errors are returned as *{{ .Prefix }}HttpError[E] where E is the error type. +type Simple{{ .Prefix }}Initiator struct { + *{{ .Prefix }}Initiator +} + +// NewSimple{{ .Prefix }}Initiator creates a new Simple{{ .Prefix }}Initiator which wraps a {{ .Prefix }}Initiator. +func NewSimple{{ .Prefix }}Initiator(opts ...{{ .Prefix }}InitiatorOption) (*Simple{{ .Prefix }}Initiator, error) { + initiator, err := New{{ .Prefix }}Initiator(opts...) + if err != nil { + return nil, err + } + return &Simple{{ .Prefix }}Initiator{ {{ .Prefix }}Initiator: initiator}, nil +} + +{{- range .Operations }} +{{- $op := . }} +{{- $opid := .GoOperationID }} +{{- $hasParams := .HasParams }} +{{- $paramsTypeName := .ParamsTypeName }} + +{{- /* Determine if this operation is "simple" - single success content type, single JSON success response */}} +{{- $simpleOp := isSimpleOperation . }} +{{- if $simpleOp }} +{{- $successResponse := simpleOperationSuccessResponse . }} +{{- $successContent := index $successResponse.Contents 0 }} +{{- $successType := goTypeForContent $successContent }} +{{- $errorResponse := errorResponseForOperation . }} + +// {{ $opid }} sends a {{ .Method }} {{ $.PrefixLower }} request and returns the parsed response. +{{ if .Summary }}// {{ .Summary }}{{ end }} +{{- if $errorResponse }} +{{- $errorContent := index $errorResponse.Contents 0 }} +{{- $errorType := goTypeForContent $errorContent }} +// On success, returns the response body. On HTTP error, returns *{{ $.Prefix }}HttpError[{{ $errorType }}]. +func (p *Simple{{ $.Prefix }}Initiator) {{ $opid }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { + var result {{ $successType }} +{{- if .HasBody }} +{{- $defaultBody := index .Bodies 0 }} + resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, body, reqEditors...) +{{- else }} + resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, reqEditors...) +{{- end }} + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // Parse error response + var errBody {{ $errorType }} + _ = json.Unmarshal(rawBody, &errBody) // Best effort parse + return result, &{{ $.Prefix }}HttpError[{{ $errorType }}]{ + StatusCode: resp.StatusCode, + Body: errBody, + RawBody: rawBody, + } +} +{{- else }} +// On success, returns the response body. On HTTP error, returns *{{ $.Prefix }}HttpError[struct{}]. +func (p *Simple{{ $.Prefix }}Initiator) {{ $opid }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { + var result {{ $successType }} +{{- if .HasBody }} +{{- $defaultBody := index .Bodies 0 }} + resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, body, reqEditors...) +{{- else }} + resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, reqEditors...) +{{- end }} + if err != nil { + return result, err + } + defer resp.Body.Close() + + rawBody, err := io.ReadAll(resp.Body) + if err != nil { + return result, err + } + + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + if err := json.Unmarshal(rawBody, &result); err != nil { + return result, err + } + return result, nil + } + + // No typed error response defined + return result, &{{ $.Prefix }}HttpError[struct{}]{ + StatusCode: resp.StatusCode, + RawBody: rawBody, + } +} +{{- end }} +{{- end }} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl new file mode 100644 index 0000000000..403eb5c13d --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl @@ -0,0 +1,271 @@ +{{/* BindDeepObjectParam - deepObject style (always exploded) */}} + +// BindDeepObjectParam binds a deepObject-style parameter to a destination. +// DeepObject style is only valid for query parameters and must be exploded. +// Objects: ?paramName[key1]=value1¶mName[key2]=value2 -> struct{Key1, Key2} +// Nested: ?paramName[outer][inner]=value -> struct{Outer: {Inner: value}} +func BindDeepObjectParam(paramName string, queryParams url.Values, dest interface{}) error { + return UnmarshalDeepObject(dest, paramName, queryParams) +} + +// UnmarshalDeepObject unmarshals deepObject-style query parameters to a destination. +func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error { + // Find all params that look like "paramName[..." + var fieldNames []string + var fieldValues []string + searchStr := paramName + "[" + + for pName, pValues := range params { + if strings.HasPrefix(pName, searchStr) { + // Trim the parameter name prefix + pName = pName[len(paramName):] + fieldNames = append(fieldNames, pName) + if len(pValues) != 1 { + return fmt.Errorf("%s has multiple values", pName) + } + fieldValues = append(fieldValues, pValues[0]) + } + } + + // Reconstruct subscript paths + paths := make([][]string, len(fieldNames)) + for i, path := range fieldNames { + path = strings.TrimLeft(path, "[") + path = strings.TrimRight(path, "]") + paths[i] = strings.Split(path, "][") + } + + fieldPaths := makeFieldOrValue(paths, fieldValues) + return assignPathValues(dst, fieldPaths) +} + +type fieldOrValue struct { + fields map[string]fieldOrValue + value string +} + +func (f *fieldOrValue) appendPathValue(path []string, value string) { + fieldName := path[0] + if len(path) == 1 { + f.fields[fieldName] = fieldOrValue{value: value} + return + } + + pv, found := f.fields[fieldName] + if !found { + pv = fieldOrValue{ + fields: make(map[string]fieldOrValue), + } + f.fields[fieldName] = pv + } + pv.appendPathValue(path[1:], value) +} + +func makeFieldOrValue(paths [][]string, values []string) fieldOrValue { + f := fieldOrValue{ + fields: make(map[string]fieldOrValue), + } + for i := range paths { + f.appendPathValue(paths[i], values[i]) + } + return f +} + +func getFieldName(f reflect.StructField) string { + n := f.Name + tag, found := f.Tag.Lookup("json") + if found { + parts := strings.Split(tag, ",") + if parts[0] != "" { + n = parts[0] + } + } + return n +} + +func fieldIndicesByJsonTag(i interface{}) (map[string]int, error) { + t := reflect.TypeOf(i) + if t.Kind() != reflect.Struct { + return nil, errors.New("expected a struct as input") + } + + n := t.NumField() + fieldMap := make(map[string]int) + for i := 0; i < n; i++ { + field := t.Field(i) + fieldName := getFieldName(field) + fieldMap[fieldName] = i + } + return fieldMap, nil +} + +func assignPathValues(dst interface{}, pathValues fieldOrValue) error { + v := reflect.ValueOf(dst) + iv := reflect.Indirect(v) + it := iv.Type() + + switch it.Kind() { + case reflect.Map: + dstMap := reflect.MakeMap(iv.Type()) + for key, value := range pathValues.fields { + dstKey := reflect.ValueOf(key) + dstVal := reflect.New(iv.Type().Elem()) + err := assignPathValues(dstVal.Interface(), value) + if err != nil { + return fmt.Errorf("error binding map: %w", err) + } + dstMap.SetMapIndex(dstKey, dstVal.Elem()) + } + iv.Set(dstMap) + return nil + + case reflect.Slice: + sliceLength := len(pathValues.fields) + dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength) + err := assignDeepObjectSlice(dstSlice, pathValues) + if err != nil { + return fmt.Errorf("error assigning slice: %w", err) + } + iv.Set(dstSlice) + return nil + + case reflect.Struct: + // Check for Binder interface + if dst, isBinder := v.Interface().(Binder); isBinder { + return dst.Bind(pathValues.value) + } + + // Handle Date type + if it.ConvertibleTo(reflect.TypeOf(Date{})) { + var date Date + var err error + date.Time, err = time.Parse(DateFormat, pathValues.value) + if err != nil { + return fmt.Errorf("invalid date format: %w", err) + } + dst := iv + if it != reflect.TypeOf(Date{}) { + ivPtr := iv.Addr() + aPtr := ivPtr.Convert(reflect.TypeOf(&Date{})) + dst = reflect.Indirect(aPtr) + } + dst.Set(reflect.ValueOf(date)) + return nil + } + + // Handle time.Time type + if it.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tm, err := time.Parse(time.RFC3339Nano, pathValues.value) + if err != nil { + tm, err = time.Parse(DateFormat, pathValues.value) + if err != nil { + return fmt.Errorf("error parsing '%s' as RFC3339 or date: %w", pathValues.value, err) + } + } + dst := iv + if it != reflect.TypeOf(time.Time{}) { + ivPtr := iv.Addr() + aPtr := ivPtr.Convert(reflect.TypeOf(&time.Time{})) + dst = reflect.Indirect(aPtr) + } + dst.Set(reflect.ValueOf(tm)) + return nil + } + + // Regular struct + fieldMap, err := fieldIndicesByJsonTag(iv.Interface()) + if err != nil { + return fmt.Errorf("failed enumerating fields: %w", err) + } + for _, fieldName := range sortedFieldOrValueKeys(pathValues.fields) { + fieldValue := pathValues.fields[fieldName] + fieldIndex, found := fieldMap[fieldName] + if !found { + return fmt.Errorf("field [%s] is not present in destination object", fieldName) + } + field := iv.Field(fieldIndex) + err = assignPathValues(field.Addr().Interface(), fieldValue) + if err != nil { + return fmt.Errorf("error assigning field [%s]: %w", fieldName, err) + } + } + return nil + + case reflect.Ptr: + dstVal := reflect.New(it.Elem()) + dstPtr := dstVal.Interface() + err := assignPathValues(dstPtr, pathValues) + iv.Set(dstVal) + return err + + case reflect.Bool: + val, err := strconv.ParseBool(pathValues.value) + if err != nil { + return fmt.Errorf("expected a valid bool, got %s", pathValues.value) + } + iv.SetBool(val) + return nil + + case reflect.Float32: + val, err := strconv.ParseFloat(pathValues.value, 32) + if err != nil { + return fmt.Errorf("expected a valid float, got %s", pathValues.value) + } + iv.SetFloat(val) + return nil + + case reflect.Float64: + val, err := strconv.ParseFloat(pathValues.value, 64) + if err != nil { + return fmt.Errorf("expected a valid float, got %s", pathValues.value) + } + iv.SetFloat(val) + return nil + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val, err := strconv.ParseInt(pathValues.value, 10, 64) + if err != nil { + return fmt.Errorf("expected a valid int, got %s", pathValues.value) + } + iv.SetInt(val) + return nil + + case reflect.String: + iv.SetString(pathValues.value) + return nil + + default: + return errors.New("unhandled type: " + it.String()) + } +} + +func assignDeepObjectSlice(dst reflect.Value, pathValues fieldOrValue) error { + nValues := len(pathValues.fields) + values := make([]string, nValues) + for i := 0; i < nValues; i++ { + indexStr := strconv.Itoa(i) + fv, found := pathValues.fields[indexStr] + if !found { + return errors.New("array deepObjects must have consecutive indices") + } + values[i] = fv.value + } + + for i := 0; i < nValues; i++ { + dstElem := dst.Index(i).Addr() + err := assignPathValues(dstElem.Interface(), fieldOrValue{value: values[i]}) + if err != nil { + return fmt.Errorf("error binding array: %w", err) + } + } + return nil +} + +func sortedFieldOrValueKeys(m map[string]fieldOrValue) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} diff --git a/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl new file mode 100644 index 0000000000..6b6b6d63de --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl @@ -0,0 +1,38 @@ +{{/* BindFormParam - form style without explode */}} + +// BindFormParam binds a form-style parameter without explode to a destination. +// Form style is the default for query and cookie parameters. +// This function handles a single query parameter value (not url.Values). +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindFormParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl new file mode 100644 index 0000000000..ec0f66d692 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl @@ -0,0 +1,145 @@ +{{/* BindFormExplodeParam - form style with explode */}} + +// BindFormExplodeParam binds a form-style parameter with explode to a destination. +// Form style is the default for query and cookie parameters. +// This handles the exploded case where arrays come as multiple query params. +// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) +// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) +func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + dv := reflect.Indirect(reflect.ValueOf(dest)) + v := dv + var output interface{} + + if required { + output = dest + } else { + // For optional parameters, allocate if nil + if v.IsNil() { + t := v.Type() + newValue := reflect.New(t.Elem()) + output = newValue.Interface() + } else { + output = v.Interface() + } + v = reflect.Indirect(reflect.ValueOf(output)) + } + + t := v.Type() + k := t.Kind() + + values, found := queryParams[paramName] + + switch k { + case reflect.Slice: + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := bindSplitPartsToDestinationArray(values, output) + if err != nil { + return err + } + case reflect.Struct: + // For exploded objects, fields are spread across query params + fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) + if err != nil { + return err + } + if !fieldsPresent { + return nil + } + default: + // Primitive + if len(values) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + if len(values) != 1 { + return fmt.Errorf("multiple values for single value parameter '%s'", paramName) + } + if !found { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } + return nil + } + err := BindStringToObject(values[0], output) + if err != nil { + return err + } + } + + if !required { + dv.Set(reflect.ValueOf(output)) + } + return nil +} + +// bindParamsToExplodedObject binds query params to struct fields for exploded objects. +func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { + binder, v, t := indirectBinder(dest) + if binder != nil { + _, found := values[paramName] + if !found { + return false, nil + } + return true, BindStringToObject(values.Get(paramName), dest) + } + if t.Kind() != reflect.Struct { + return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) + } + + fieldsPresent := false + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + if !v.Field(i).CanSet() { + continue + } + + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + + fieldVal, found := values[fieldName] + if found { + if len(fieldVal) != 1 { + return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) + } + err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) + if err != nil { + return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) + } + fieldsPresent = true + } + } + return fieldsPresent, nil +} + +// indirectBinder checks if dest implements Binder and returns reflect values. +func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { + v := reflect.ValueOf(dest) + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Binder); ok { + return u, reflect.Value{}, nil + } + } + v = reflect.Indirect(v) + t := v.Type() + // Handle special types like time.Time and Date + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + return dest, reflect.Value{}, nil + } + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + return dest, reflect.Value{}, nil + } + return nil, v, t +} diff --git a/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl new file mode 100644 index 0000000000..a9bff4ab18 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl @@ -0,0 +1,46 @@ +{{/* BindLabelParam - label style without explode */}} + +// BindLabelParam binds a label-style parameter without explode to a destination. +// Label style values are prefixed with a dot. +// Primitives: .value -> "value" +// Arrays: .a,b,c -> []string{"a", "b", "c"} +// Objects: .key1,value1,key2,value2 -> struct{Key1, Key2} +func BindLabelParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Label style requires leading dot + if value[0] != '.' { + return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) + } + + // Strip the leading dot and split on comma + stripped := value[1:] + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(stripped)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + parts := strings.Split(stripped, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(stripped, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(stripped, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl new file mode 100644 index 0000000000..766d29e3ea --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl @@ -0,0 +1,51 @@ +{{/* BindLabelExplodeParam - label style with explode */}} + +// BindLabelExplodeParam binds a label-style parameter with explode to a destination. +// Label style values are prefixed with a dot. +// Primitives: .value -> "value" +// Arrays: .a.b.c -> []string{"a", "b", "c"} +// Objects: .key1=value1.key2=value2 -> struct{Key1, Key2} +func BindLabelExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Label style requires leading dot + if value[0] != '.' { + return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value[1:])) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on dot (skip first empty part) + parts := strings.Split(value, ".") + if parts[0] != "" { + return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) + } + return bindSplitPartsToDestinationStruct(paramName, parts[1:], true, dest) + case reflect.Slice: + // Split on dot (skip first empty part) + parts := strings.Split(value, ".") + if parts[0] != "" { + return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) + } + return bindSplitPartsToDestinationArray(parts[1:], dest) + default: + return BindStringToObject(value[1:], dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl new file mode 100644 index 0000000000..0702dfa755 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl @@ -0,0 +1,47 @@ +{{/* BindMatrixParam - matrix style without explode */}} + +// BindMatrixParam binds a matrix-style parameter without explode to a destination. +// Matrix style values are prefixed with ;paramName=. +// Primitives: ;paramName=value -> "value" +// Arrays: ;paramName=a,b,c -> []string{"a", "b", "c"} +// Objects: ;paramName=key1,value1,key2,value2 -> struct{Key1, Key2} +func BindMatrixParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Matrix style requires ;paramName= prefix + prefix := ";" + paramName + "=" + if !strings.HasPrefix(value, prefix) { + return fmt.Errorf("expected parameter '%s' to start with %s", paramName, prefix) + } + + // Strip the prefix + stripped := strings.TrimPrefix(value, prefix) + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(stripped)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + parts := strings.Split(stripped, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(stripped, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(stripped, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl new file mode 100644 index 0000000000..0b2f7ffd9a --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl @@ -0,0 +1,65 @@ +{{/* BindMatrixExplodeParam - matrix style with explode */}} + +// BindMatrixExplodeParam binds a matrix-style parameter with explode to a destination. +// Matrix style values are prefixed with semicolons. +// Primitives: ;paramName=value -> "value" +// Arrays: ;paramName=a;paramName=b;paramName=c -> []string{"a", "b", "c"} +// Objects: ;key1=value1;key2=value2 -> struct{Key1, Key2} +func BindMatrixExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Break up on semicolon + parts := strings.Split(value, ";") + // First part should be empty since we start with ; + if parts[0] != "" { + return fmt.Errorf("invalid format for matrix parameter '%s', should start with ';'", paramName) + } + parts = parts[1:] + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + // For primitives, should be ;paramName=value + if len(parts) == 1 { + kv := strings.SplitN(parts[0], "=", 2) + if len(kv) == 2 && kv[0] == paramName { + return tu.UnmarshalText([]byte(kv[1])) + } + } + return fmt.Errorf("invalid format for matrix parameter '%s'", paramName) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // For objects, we have key1=value1, key2=value2 + return bindSplitPartsToDestinationStruct(paramName, parts, true, dest) + case reflect.Slice: + // For arrays, strip paramName= prefix from each part + prefix := paramName + "=" + values := make([]string, len(parts)) + for i, part := range parts { + values[i] = strings.TrimPrefix(part, prefix) + } + return bindSplitPartsToDestinationArray(values, dest) + default: + // Primitive: ;paramName=value + if len(parts) == 1 { + kv := strings.SplitN(parts[0], "=", 2) + if len(kv) == 2 && kv[0] == paramName { + return BindStringToObject(kv[1], dest) + } + } + return fmt.Errorf("invalid format for matrix parameter '%s'", paramName) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl new file mode 100644 index 0000000000..1adfd9ef3e --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl @@ -0,0 +1,33 @@ +{{/* BindPipeDelimitedParam - pipeDelimited style without explode */}} + +// BindPipeDelimitedParam binds a pipeDelimited-style parameter without explode. +// Pipe-delimited style uses pipe as the separator. +// Arrays: a|b|c -> []string{"a", "b", "c"} +func BindPipeDelimitedParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Slice: + parts := strings.Split(value, "|") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl new file mode 100644 index 0000000000..9af6d4a5f3 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl @@ -0,0 +1,9 @@ +{{/* BindPipeDelimitedExplodeParam - pipeDelimited style with explode */}} + +// BindPipeDelimitedExplodeParam binds a pipeDelimited-style parameter with explode. +// When exploded, arrays come as multiple query params (same as form explode). +// Arrays: ?param=a¶m=b -> []string{"a", "b"} +func BindPipeDelimitedExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + // Exploded pipe-delimited is same as exploded form + return BindFormExplodeParam(paramName, required, queryParams, dest) +} diff --git a/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl new file mode 100644 index 0000000000..3b48a81c15 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl @@ -0,0 +1,38 @@ +{{/* BindSimpleParam - simple style without explode */}} + +// BindSimpleParam binds a simple-style parameter without explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} +// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} +func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key,value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl new file mode 100644 index 0000000000..3d9468f26a --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl @@ -0,0 +1,38 @@ +{{/* BindSimpleExplodeParam - simple style with explode */}} + +// BindSimpleExplodeParam binds a simple-style parameter with explode to a destination. +// Simple style is the default for path and header parameters. +// Arrays: a,b,c -> []string{"a", "b", "c"} (same as non-explode) +// Objects: key1=value1,key2=value2 -> struct{Key1, Key2} +func BindSimpleExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Struct: + // Split on comma and bind as key=value pairs + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationStruct(paramName, parts, true, dest) + case reflect.Slice: + parts := strings.Split(value, ",") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl new file mode 100644 index 0000000000..b7b83685df --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl @@ -0,0 +1,33 @@ +{{/* BindSpaceDelimitedParam - spaceDelimited style without explode */}} + +// BindSpaceDelimitedParam binds a spaceDelimited-style parameter without explode. +// Space-delimited style uses space as the separator. +// Arrays: a b c -> []string{"a", "b", "c"} +func BindSpaceDelimitedParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { + if value == "" { + return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) + } + + // Unescape based on location + var err error + value, err = unescapeParameterString(value, paramLocation) + if err != nil { + return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) + } + + // Check for TextUnmarshaler + if tu, ok := dest.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(value)) + } + + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + switch t.Kind() { + case reflect.Slice: + parts := strings.Split(value, " ") + return bindSplitPartsToDestinationArray(parts, dest) + default: + return BindStringToObject(value, dest) + } +} diff --git a/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl new file mode 100644 index 0000000000..f79f097eff --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl @@ -0,0 +1,9 @@ +{{/* BindSpaceDelimitedExplodeParam - spaceDelimited style with explode */}} + +// BindSpaceDelimitedExplodeParam binds a spaceDelimited-style parameter with explode. +// When exploded, arrays come as multiple query params (same as form explode). +// Arrays: ?param=a¶m=b -> []string{"a", "b"} +func BindSpaceDelimitedExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { + // Exploded space-delimited is same as exploded form + return BindFormExplodeParam(paramName, required, queryParams, dest) +} diff --git a/experimental/internal/codegen/templates/files/params/helpers.go.tmpl b/experimental/internal/codegen/templates/files/params/helpers.go.tmpl new file mode 100644 index 0000000000..b3f650f211 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/helpers.go.tmpl @@ -0,0 +1,260 @@ +{{/* Parameter styling and binding helper functions - included when any param function is used */}} + +// ParamLocation indicates where a parameter is located in an HTTP request. +type ParamLocation int + +const ( + ParamLocationUndefined ParamLocation = iota + ParamLocationQuery + ParamLocationPath + ParamLocationHeader + ParamLocationCookie +) + +// Binder is an interface for types that can bind themselves from a string value. +type Binder interface { + Bind(value string) error +} + +// DateFormat is the format used for date (without time) parameters. +const DateFormat = "2006-01-02" + +// Date represents a date (without time) for OpenAPI date format. +type Date struct { + time.Time +} + +// UnmarshalText implements encoding.TextUnmarshaler for Date. +func (d *Date) UnmarshalText(data []byte) error { + t, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = t + return nil +} + +// MarshalText implements encoding.TextMarshaler for Date. +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + +// Format returns the date formatted according to layout. +func (d Date) Format(layout string) string { + return d.Time.Format(layout) +} + +// primitiveToString converts a primitive value to a string representation. +// It handles basic Go types, time.Time, types.Date, and types that implement +// json.Marshaler or fmt.Stringer. +func primitiveToString(value interface{}) (string, error) { + // Check for known types first (time, date, uuid) + if res, ok := marshalKnownTypes(value); ok { + return res, nil + } + + // Dereference pointers for optional values + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + kind := t.Kind() + + switch kind { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Bool: + if v.Bool() { + return "true", nil + } + return "false", nil + case reflect.String: + return v.String(), nil + case reflect.Struct: + // Check if it's a UUID + if u, ok := value.(uuid.UUID); ok { + return u.String(), nil + } + // Check if it implements json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + var i2 interface{} + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to decode JSON: %w", err) + } + return primitiveToString(i2) + } + fallthrough + default: + if s, ok := value.(fmt.Stringer); ok { + return s.String(), nil + } + return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) + } +} + +// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. +func marshalKnownTypes(value interface{}) (string, bool) { + v := reflect.Indirect(reflect.ValueOf(value)) + t := v.Type() + + if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { + tt := v.Convert(reflect.TypeOf(time.Time{})) + timeVal := tt.Interface().(time.Time) + return timeVal.Format(time.RFC3339Nano), true + } + + if t.ConvertibleTo(reflect.TypeOf(Date{})) { + d := v.Convert(reflect.TypeOf(Date{})) + dateVal := d.Interface().(Date) + return dateVal.Format(DateFormat), true + } + + if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { + u := v.Convert(reflect.TypeOf(uuid.UUID{})) + uuidVal := u.Interface().(uuid.UUID) + return uuidVal.String(), true + } + + return "", false +} + +// escapeParameterString escapes a parameter value based on its location. +// Query and path parameters need URL escaping; headers and cookies do not. +func escapeParameterString(value string, paramLocation ParamLocation) string { + switch paramLocation { + case ParamLocationQuery: + return url.QueryEscape(value) + case ParamLocationPath: + return url.PathEscape(value) + default: + return value + } +} + +// unescapeParameterString unescapes a parameter value based on its location. +func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { + switch paramLocation { + case ParamLocationQuery, ParamLocationUndefined: + return url.QueryUnescape(value) + case ParamLocationPath: + return url.PathUnescape(value) + default: + return value, nil + } +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// BindStringToObject binds a string value to a destination object. +// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. +func BindStringToObject(src string, dst interface{}) error { + // Check for TextUnmarshaler + if tu, ok := dst.(encoding.TextUnmarshaler); ok { + return tu.UnmarshalText([]byte(src)) + } + + // Check for Binder interface + if b, ok := dst.(Binder); ok { + return b.Bind(src) + } + + v := reflect.ValueOf(dst) + if v.Kind() != reflect.Ptr { + return fmt.Errorf("dst must be a pointer, got %T", dst) + } + v = v.Elem() + + switch v.Kind() { + case reflect.String: + v.SetString(src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i, err := strconv.ParseInt(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int: %w", err) + } + v.SetInt(i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u, err := strconv.ParseUint(src, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint: %w", err) + } + v.SetUint(u) + case reflect.Float32, reflect.Float64: + f, err := strconv.ParseFloat(src, 64) + if err != nil { + return fmt.Errorf("failed to parse float: %w", err) + } + v.SetFloat(f) + case reflect.Bool: + b, err := strconv.ParseBool(src) + if err != nil { + return fmt.Errorf("failed to parse bool: %w", err) + } + v.SetBool(b) + default: + // Try JSON unmarshal as a fallback + return json.Unmarshal([]byte(src), dst) + } + return nil +} + +// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. +func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { + v := reflect.Indirect(reflect.ValueOf(dest)) + t := v.Type() + + newArray := reflect.MakeSlice(t, len(parts), len(parts)) + for i, p := range parts { + err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) + if err != nil { + return fmt.Errorf("error setting array element: %w", err) + } + } + v.Set(newArray) + return nil +} + +// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. +func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { + var fields []string + if explode { + fields = make([]string, len(parts)) + for i, property := range parts { + propertyParts := strings.Split(property, "=") + if len(propertyParts) != 2 { + return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) + } + fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" + } + } else { + if len(parts)%2 != 0 { + return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) + } + fields = make([]string, len(parts)/2) + for i := 0; i < len(parts); i += 2 { + key := parts[i] + value := parts[i+1] + fields[i/2] = "\"" + key + "\":\"" + value + "\"" + } + } + jsonParam := "{" + strings.Join(fields, ",") + "}" + return json.Unmarshal([]byte(jsonParam), dest) +} diff --git a/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl b/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl new file mode 100644 index 0000000000..753ff4433a --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl @@ -0,0 +1,74 @@ +{{/* StyleDeepObjectParam - deepObject style (always exploded) */}} + +// StyleDeepObjectParam serializes a value using deepObject style. +// DeepObject style is only valid for query parameters with object values and must be exploded. +// Objects: paramName[key1]=value1¶mName[key2]=value2 +// Nested: paramName[outer][inner]=value +func StyleDeepObjectParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // deepObject always requires explode=true + return MarshalDeepObject(value, paramName) +} + +// MarshalDeepObject marshals an object to deepObject style query parameters. +func MarshalDeepObject(i interface{}, paramName string) (string, error) { + // Marshal to JSON first to handle all field annotations + buf, err := json.Marshal(i) + if err != nil { + return "", fmt.Errorf("failed to marshal input to JSON: %w", err) + } + var i2 interface{} + err = json.Unmarshal(buf, &i2) + if err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + fields, err := marshalDeepObjectRecursive(i2, nil) + if err != nil { + return "", fmt.Errorf("error traversing JSON structure: %w", err) + } + + // Prefix the param name to each subscripted field + for idx := range fields { + fields[idx] = paramName + fields[idx] + } + return strings.Join(fields, "&"), nil +} + +func marshalDeepObjectRecursive(in interface{}, path []string) ([]string, error) { + var result []string + + switch t := in.(type) { + case []interface{}: + // Arrays use numerical subscripts [0], [1], etc. + for i, iface := range t { + newPath := append(path, strconv.Itoa(i)) + fields, err := marshalDeepObjectRecursive(iface, newPath) + if err != nil { + return nil, fmt.Errorf("error traversing array: %w", err) + } + result = append(result, fields...) + } + case map[string]interface{}: + // Maps use key subscripts [key1], [key2], etc. + keys := make([]string, 0, len(t)) + for k := range t { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + newPath := append(path, k) + fields, err := marshalDeepObjectRecursive(t[k], newPath) + if err != nil { + return nil, fmt.Errorf("error traversing map: %w", err) + } + result = append(result, fields...) + } + default: + // Concrete value: turn path into [a][b][c] format + prefix := "[" + strings.Join(path, "][") + "]" + result = []string{ + prefix + fmt.Sprintf("=%v", t), + } + } + return result, nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_form.go.tmpl b/experimental/internal/codegen/templates/files/params/style_form.go.tmpl new file mode 100644 index 0000000000..91df97e6e0 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_form.go.tmpl @@ -0,0 +1,132 @@ +{{/* StyleFormParam - form style without explode */}} + +// StyleFormParam serializes a value using form style (RFC 6570) without exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a,b,c +// Objects: paramName=key1,value1,key2,value2 +func StyleFormParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormMap(paramName, paramLocation, value) + default: + return styleFormPrimitive(paramName, paramLocation, value) + } +} + +func styleFormPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form without explode: paramName=a,b,c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, ","), nil +} + +func styleFormStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style without explode: paramName=key1,value1,key2,value2 + prefix := fmt.Sprintf("%s=", paramName) + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return prefix + strings.Join(parts, ","), nil +} + +func styleFormMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style without explode: paramName=key1,value1,key2,value2 + prefix := fmt.Sprintf("%s=", paramName) + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return prefix + strings.Join(parts, ","), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl new file mode 100644 index 0000000000..a39c67c21b --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl @@ -0,0 +1,130 @@ +{{/* StyleFormExplodeParam - form style with explode */}} + +// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. +// Form style is the default for query and cookie parameters. +// Primitives: paramName=value +// Arrays: paramName=a¶mName=b¶mName=c +// Objects: key1=value1&key2=value2 +func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleFormExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleFormExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleFormExplodeMap(paramName, paramLocation, value) + default: + return styleFormExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Form with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} + +func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleFormExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} + +func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Form style with explode: key1=value1&key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, "&"), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_label.go.tmpl b/experimental/internal/codegen/templates/files/params/style_label.go.tmpl new file mode 100644 index 0000000000..def8c74ee0 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_label.go.tmpl @@ -0,0 +1,129 @@ +{{/* StyleLabelParam - label style without explode */}} + +// StyleLabelParam serializes a value using label style (RFC 6570) without exploding. +// Label style prefixes values with a dot. +// Primitives: .value +// Arrays: .a,b,c +// Objects: .key1,value1,key2,value2 +func StyleLabelParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return "." + escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleLabelSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleLabelStruct(paramName, paramLocation, value) + case reflect.Map: + return styleLabelMap(paramName, paramLocation, value) + default: + return styleLabelPrimitive(paramLocation, value) + } +} + +func styleLabelPrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return "." + escapeParameterString(strVal, paramLocation), nil +} + +func styleLabelSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Label without explode: .a,b,c + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return "." + strings.Join(parts, ","), nil +} + +func styleLabelStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return "." + escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleLabelParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Label style without explode: .key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return "." + strings.Join(parts, ","), nil +} + +func styleLabelMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Label style without explode: .key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return "." + strings.Join(parts, ","), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl new file mode 100644 index 0000000000..c770480811 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl @@ -0,0 +1,129 @@ +{{/* StyleLabelExplodeParam - label style with explode */}} + +// StyleLabelExplodeParam serializes a value using label style (RFC 6570) with exploding. +// Label style prefixes values with a dot. +// Primitives: .value +// Arrays: .a.b.c +// Objects: .key1=value1.key2=value2 +func StyleLabelExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return "." + escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleLabelExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleLabelExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleLabelExplodeMap(paramName, paramLocation, value) + default: + return styleLabelExplodePrimitive(paramLocation, value) + } +} + +func styleLabelExplodePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return "." + escapeParameterString(strVal, paramLocation), nil +} + +func styleLabelExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Label with explode: .a.b.c + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return "." + strings.Join(parts, "."), nil +} + +func styleLabelExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return "." + escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleLabelExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Label style with explode: .key1=value1.key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return "." + strings.Join(parts, "."), nil +} + +func styleLabelExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Label style with explode: .key1=value1.key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return "." + strings.Join(parts, "."), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl b/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl new file mode 100644 index 0000000000..49c001f9dc --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl @@ -0,0 +1,132 @@ +{{/* StyleMatrixParam - matrix style without explode */}} + +// StyleMatrixParam serializes a value using matrix style (RFC 6570) without exploding. +// Matrix style prefixes values with ;paramName=. +// Primitives: ;paramName=value +// Arrays: ;paramName=a,b,c +// Objects: ;paramName=key1,value1,key2,value2 +func StyleMatrixParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleMatrixSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleMatrixStruct(paramName, paramLocation, value) + case reflect.Map: + return styleMatrixMap(paramName, paramLocation, value) + default: + return styleMatrixPrimitive(paramName, paramLocation, value) + } +} + +func styleMatrixPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleMatrixSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Matrix without explode: ;paramName=a,b,c + prefix := fmt.Sprintf(";%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, ","), nil +} + +func styleMatrixStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleMatrixParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Matrix style without explode: ;paramName=key1,value1,key2,value2 + prefix := fmt.Sprintf(";%s=", paramName) + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return prefix + strings.Join(parts, ","), nil +} + +func styleMatrixMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Matrix style without explode: ;paramName=key1,value1,key2,value2 + prefix := fmt.Sprintf(";%s=", paramName) + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return prefix + strings.Join(parts, ","), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl new file mode 100644 index 0000000000..63790426f4 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl @@ -0,0 +1,130 @@ +{{/* StyleMatrixExplodeParam - matrix style with explode */}} + +// StyleMatrixExplodeParam serializes a value using matrix style (RFC 6570) with exploding. +// Matrix style prefixes values with ;paramName=. +// Primitives: ;paramName=value +// Arrays: ;paramName=a;paramName=b;paramName=c +// Objects: ;key1=value1;key2=value2 +func StyleMatrixExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleMatrixExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleMatrixExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleMatrixExplodeMap(paramName, paramLocation, value) + default: + return styleMatrixExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleMatrixExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleMatrixExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Matrix with explode: ;paramName=a;paramName=b;paramName=c + prefix := fmt.Sprintf(";%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, prefix), nil +} + +func styleMatrixExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleMatrixExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Matrix style with explode: ;key1=value1;key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return ";" + strings.Join(parts, ";"), nil +} + +func styleMatrixExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Matrix style with explode: ;key1=value1;key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return ";" + strings.Join(parts, ";"), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl new file mode 100644 index 0000000000..de7022ecda --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl @@ -0,0 +1,66 @@ +{{/* StylePipeDelimitedParam - pipeDelimited style without explode */}} + +// StylePipeDelimitedParam serializes a value using pipeDelimited style without exploding. +// Pipe-delimited style is used for query parameters with array values. +// Arrays: paramName=a|b|c +// Note: Only valid for arrays; objects should use other styles. +func StylePipeDelimitedParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return stylePipeDelimitedSlice(paramName, paramLocation, sliceVal) + default: + // For primitives, fall back to form style + return stylePipeDelimitedPrimitive(paramName, paramLocation, value) + } +} + +func stylePipeDelimitedPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func stylePipeDelimitedSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Pipe-delimited without explode: paramName=a|b|c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "|"), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl new file mode 100644 index 0000000000..fa156dea7e --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl @@ -0,0 +1,66 @@ +{{/* StylePipeDelimitedExplodeParam - pipeDelimited style with explode */}} + +// StylePipeDelimitedExplodeParam serializes a value using pipeDelimited style with exploding. +// Pipe-delimited style is used for query parameters with array values. +// Arrays: paramName=a¶mName=b¶mName=c (same as form explode) +// Note: Only valid for arrays; objects should use other styles. +func StylePipeDelimitedExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return stylePipeDelimitedExplodeSlice(paramName, paramLocation, sliceVal) + default: + // For primitives, fall back to form style + return stylePipeDelimitedExplodePrimitive(paramName, paramLocation, value) + } +} + +func stylePipeDelimitedExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func stylePipeDelimitedExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Pipe-delimited with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl b/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl new file mode 100644 index 0000000000..7476b2d4a4 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl @@ -0,0 +1,158 @@ +{{/* StyleSimpleParam - simple style without explode */}} + +// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c +// Objects are key,value pairs: key1,value1,key2,value2 +func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleMap(paramName, paramLocation, value) + default: + return styleSimplePrimitive(paramLocation, value) + } +} + +func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style without explode: key1,value1,key2,value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k, v) + } + return strings.Join(parts, ","), nil +} + +// structToFieldDict converts a struct to a map of field names to string values. +func structToFieldDict(value interface{}) (map[string]string, error) { + v := reflect.ValueOf(value) + t := reflect.TypeOf(value) + fieldDict := make(map[string]string) + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i) + tag := fieldT.Tag.Get("json") + fieldName := fieldT.Name + if tag != "" { + tagParts := strings.Split(tag, ",") + if tagParts[0] != "" { + fieldName = tagParts[0] + } + } + f := v.Field(i) + + // Skip nil optional fields + if f.Type().Kind() == reflect.Ptr && f.IsNil() { + continue + } + str, err := primitiveToString(f.Interface()) + if err != nil { + return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) + } + fieldDict[fieldName] = str + } + return fieldDict, nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl new file mode 100644 index 0000000000..38dc6d3983 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl @@ -0,0 +1,128 @@ +{{/* StyleSimpleExplodeParam - simple style with explode */}} + +// StyleSimpleExplodeParam serializes a value using simple style (RFC 6570) with exploding. +// Simple style is the default for path and header parameters. +// Arrays are comma-separated: a,b,c (same as non-explode) +// Objects are key=value pairs: key1=value1,key2=value2 +func StyleSimpleExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return escapeParameterString(string(b), paramLocation), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSimpleExplodeSlice(paramName, paramLocation, sliceVal) + case reflect.Struct: + return styleSimpleExplodeStruct(paramName, paramLocation, value) + case reflect.Map: + return styleSimpleExplodeMap(paramName, paramLocation, value) + default: + return styleSimpleExplodePrimitive(paramLocation, value) + } +} + +func styleSimpleExplodePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return escapeParameterString(strVal, paramLocation), nil +} + +func styleSimpleExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Exploded simple array is same as non-exploded: comma-separated + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + // Check for known types first + if timeVal, ok := marshalKnownTypes(value); ok { + return escapeParameterString(timeVal, paramLocation), nil + } + + // Check for json.Marshaler + if m, ok := value.(json.Marshaler); ok { + buf, err := m.MarshalJSON() + if err != nil { + return "", fmt.Errorf("failed to marshal to JSON: %w", err) + } + var i2 interface{} + e := json.NewDecoder(bytes.NewReader(buf)) + e.UseNumber() + if err = e.Decode(&i2); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON: %w", err) + } + return StyleSimpleExplodeParam(paramName, paramLocation, i2) + } + + // Build field dictionary + fieldDict, err := structToFieldDict(value) + if err != nil { + return "", err + } + + // Simple style with explode: key1=value1,key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, ","), nil +} + +func styleSimpleExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + dict, ok := value.(map[string]interface{}) + if !ok { + return "", errors.New("map not of type map[string]interface{}") + } + + fieldDict := make(map[string]string) + for fieldName, val := range dict { + str, err := primitiveToString(val) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + fieldDict[fieldName] = str + } + + // Simple style with explode: key1=value1,key2=value2 + var parts []string + for _, k := range sortedKeys(fieldDict) { + v := escapeParameterString(fieldDict[k], paramLocation) + parts = append(parts, k+"="+v) + } + return strings.Join(parts, ","), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl new file mode 100644 index 0000000000..7256e3a43c --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl @@ -0,0 +1,66 @@ +{{/* StyleSpaceDelimitedParam - spaceDelimited style without explode */}} + +// StyleSpaceDelimitedParam serializes a value using spaceDelimited style without exploding. +// Space-delimited style is used for query parameters with array values. +// Arrays: paramName=a b c (space-separated) +// Note: Only valid for arrays; objects should use other styles. +func StyleSpaceDelimitedParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSpaceDelimitedSlice(paramName, paramLocation, sliceVal) + default: + // For primitives, fall back to form style + return styleSpaceDelimitedPrimitive(paramName, paramLocation, value) + } +} + +func styleSpaceDelimitedPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleSpaceDelimitedSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Space-delimited without explode: paramName=a b c (space becomes %20 when encoded) + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, " "), nil +} diff --git a/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl new file mode 100644 index 0000000000..e32813ba91 --- /dev/null +++ b/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl @@ -0,0 +1,66 @@ +{{/* StyleSpaceDelimitedExplodeParam - spaceDelimited style with explode */}} + +// StyleSpaceDelimitedExplodeParam serializes a value using spaceDelimited style with exploding. +// Space-delimited style is used for query parameters with array values. +// Arrays: paramName=a¶mName=b¶mName=c (same as form explode) +// Note: Only valid for arrays; objects should use other styles. +func StyleSpaceDelimitedExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + // Dereference pointers + if t.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("value is a nil pointer") + } + v = reflect.Indirect(v) + t = v.Type() + } + + // Check for TextMarshaler (but not time.Time or Date) + if tu, ok := value.(encoding.TextMarshaler); ok { + innerT := reflect.Indirect(reflect.ValueOf(value)).Type() + if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { + b, err := tu.MarshalText() + if err != nil { + return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil + } + } + + switch t.Kind() { + case reflect.Slice: + n := v.Len() + sliceVal := make([]interface{}, n) + for i := 0; i < n; i++ { + sliceVal[i] = v.Index(i).Interface() + } + return styleSpaceDelimitedExplodeSlice(paramName, paramLocation, sliceVal) + default: + // For primitives, fall back to form style + return styleSpaceDelimitedExplodePrimitive(paramName, paramLocation, value) + } +} + +func styleSpaceDelimitedExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { + strVal, err := primitiveToString(value) + if err != nil { + return "", err + } + return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil +} + +func styleSpaceDelimitedExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { + // Space-delimited with explode: paramName=a¶mName=b¶mName=c + prefix := fmt.Sprintf("%s=", paramName) + parts := make([]string, len(values)) + for i, v := range values { + part, err := primitiveToString(v) + if err != nil { + return "", fmt.Errorf("error formatting '%s': %w", paramName, err) + } + parts[i] = escapeParameterString(part, paramLocation) + } + return prefix + strings.Join(parts, "&"+prefix), nil +} diff --git a/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl new file mode 100644 index 0000000000..ccd9653b40 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl @@ -0,0 +1,59 @@ +{{- /* + This template generates the HTTP handler and routing for Chi servers. + Input: []OperationDescriptor +*/ -}} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, ChiServerOptions{}) +} + +// ChiServerOptions configures the Chi server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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) + } + } +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, + } +{{ end }} +{{- range . }} + r.Group(func(r chi.Router) { + r.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToChiPattern .Path }}", wrapper.{{ .GoOperationID }}) + }) +{{- end }} + return r +} diff --git a/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl new file mode 100644 index 0000000000..010ed1b157 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Chi servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { + w.WriteHeader(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl new file mode 100644 index 0000000000..dce41f1d14 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl @@ -0,0 +1,95 @@ +{{- /* + This template generates the receiver interface and handler functions for Chi. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. +type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) + return + }{{ end }} +{{ end }} +{{- end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl new file mode 100644 index 0000000000..91d346b682 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl @@ -0,0 +1,166 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Chi. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +{{ range . }} +// {{ .GoOperationID }} operation middleware +func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = chi.URLParam(r, "{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(chi.URLParam(r, "{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, chi.URLParam(r, "{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{- if .Security }} + ctx := r.Context() +{{- range .Security }} + ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} + r = r.WithContext(ctx) +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := r.Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") + siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) + return + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + { + var cookie *http.Cookie + if cookie, err = r.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie.Value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} + } +{{ end }} +{{ end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl new file mode 100644 index 0000000000..fcbb54b60d --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl @@ -0,0 +1,34 @@ +{{- /* + This template generates the HTTP handler and routing for Echo servers. + Input: []OperationDescriptor +*/ -}} + +// EchoRouter is an interface for echo.Echo and echo.Group. +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, "") +} + +// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. +func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + } +{{ end }} +{{- range . }} + router.{{ .Method }}(baseURL+"{{ pathToEchoPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl new file mode 100644 index 0000000000..22cb0ebe68 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Echo servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(ctx echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(ctx echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { + return ctx.NoContent(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl new file mode 100644 index 0000000000..0fa1b97708 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl @@ -0,0 +1,72 @@ +{{- /* + This template generates the receiver interface and handler functions for Echo v4. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx echo.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an echo.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) echo.HandlerFunc { + return func(ctx echo.Context) error { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query parameter {{ .Name }} is required")) + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required")) + }{{ end }} +{{ end }} +{{- end }} + return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) + } +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl new file mode 100644 index 0000000000..6847388a7e --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl @@ -0,0 +1,134 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Echo. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +{{ range . }} +// {{ .GoOperationID }} converts echo context to params. +func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx echo.Context) error { + var err error + +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = ctx.Param("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(ctx.Param("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Param("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{- if .Security }} +{{- range .Security }} + ctx.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- else }} + if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) + }{{ end }} +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := ctx.Request().Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required, but not found")) + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + if cookie, err := ctx.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie.Value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) + }{{ end }} +{{ end }} +{{ end }} + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) + return err +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl new file mode 100644 index 0000000000..0e6d2dbd01 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl @@ -0,0 +1,35 @@ +{{- /* + This template generates the HTTP handler and routing for Echo v5 servers. + Input: []OperationDescriptor +*/ -}} + +// EchoRouter is an interface for echo.Echo and echo.Group. +type EchoRouter interface { + Add(method string, path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo + 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 +} + +// RegisterHandlers adds each server route to the EchoRouter. +func RegisterHandlers(router EchoRouter, si ServerInterface) { + RegisterHandlersWithBaseURL(router, si, "") +} + +// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. +func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + } +{{ end }} +{{- range . }} + router.{{ .Method }}(baseURL+"{{ pathToEchoPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl new file mode 100644 index 0000000000..e1c4ac779a --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Echo v5 servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(ctx *echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(ctx *echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { + return ctx.NoContent(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl new file mode 100644 index 0000000000..8a336c5e23 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl @@ -0,0 +1,72 @@ +{{- /* + This template generates the receiver interface and handler functions for Echo v5. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx *echo.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an echo.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) echo.HandlerFunc { + return func(ctx *echo.Context) error { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query parameter {{ .Name }} is required")) + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required")) + }{{ end }} +{{ end }} +{{- end }} + return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) + } +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl new file mode 100644 index 0000000000..ae92e02879 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl @@ -0,0 +1,134 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Echo v5. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts echo contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +{{ range . }} +// {{ .GoOperationID }} converts echo context to params. +func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx *echo.Context) error { + var err error + +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = ctx.Param("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(ctx.Param("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Param("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{- if .Security }} +{{- range .Security }} + ctx.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- else }} + if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) + }{{ end }} +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := ctx.Request().Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required, but not found")) + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + if cookie, err := ctx.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie.Value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) + }{{ end }} +{{ end }} +{{ end }} + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) + return err +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/errors.go.tmpl b/experimental/internal/codegen/templates/files/server/errors.go.tmpl new file mode 100644 index 0000000000..c4727ef976 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/errors.go.tmpl @@ -0,0 +1,79 @@ +{{- /* + This template generates error types for server parameter handling. + These are shared across all router implementations. +*/ -}} + +// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. +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 +} + +// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. +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 +} + +// RequiredParamError is returned when a required parameter is missing. +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +// RequiredHeaderError is returned when a required header is missing. +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 +} + +// InvalidParamFormatError is returned when a parameter has an invalid format. +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 +} + +// TooManyValuesForParamError is returned when a parameter has too many values. +type TooManyValuesForParamError struct { + ParamName string + Count int +} + +func (e *TooManyValuesForParamError) Error() string { + return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) +} diff --git a/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl new file mode 100644 index 0000000000..b6e59cfb75 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl @@ -0,0 +1,31 @@ +{{- /* + This template generates the HTTP handler and routing for Fiber servers. + Input: []OperationDescriptor +*/ -}} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []fiber.Handler +} + +// 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) { +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + } + + for _, m := range options.Middlewares { + router.Use(m) + } +{{ end }} +{{- range . }} + router.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToFiberPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl new file mode 100644 index 0000000000..dddefc81c6 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Fiber servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(c fiber.Ctx{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(c fiber.Ctx{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { + return c.SendStatus(fiber.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl new file mode 100644 index 0000000000..5775f45ed1 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl @@ -0,0 +1,71 @@ +{{- /* + This template generates the receiver interface and handler functions for Fiber. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(c fiber.Ctx{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error +{{- end }} +} + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns a fiber.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) fiber.Handler { + return func(c fiber.Ctx) error { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := c.Query("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return fiber.NewError(http.StatusBadRequest, "Query parameter {{ .Name }} is required") + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Queries(), ¶ms.{{ .GoName }}) + if err != nil { + return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + { + headerValue := c.Get("{{ .Name }}") + if headerValue != "" { + var {{ .GoVariableName }} {{ .TypeDecl }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, headerValue, &{{ .GoVariableName }}) + if err != nil { + return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return fiber.NewError(http.StatusBadRequest, "Header parameter {{ .Name }} is required") + }{{ end }} + } +{{ end }} +{{- end }} + return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(c{{ if .HasParams }}, params{{ end }}) + } +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl new file mode 100644 index 0000000000..7abbd2da7a --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl @@ -0,0 +1,137 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Fiber. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +{{ range . }} +// {{ .GoOperationID }} operation middleware +func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c fiber.Ctx) error { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = c.Params("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(c.Params("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, c.Params("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} +{{ end }} +{{- if .Security }} +{{- range .Security }} + c.Locals({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ if .QueryParams }} + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for query string: %s", err)) + } +{{ end }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, query, ¶ms.{{ .GoName }}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- else if or .Required .IsPassThrough .IsJSON }} + if paramValue := c.Query("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return fiber.NewError(fiber.StatusBadRequest, "Query argument {{ .Name }} is required, but not found") + }{{ end }} +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := c.GetReqHeaders() +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found && len(valueList) > 0 { + var {{ .GoVariableName }} {{ .TypeDecl }} + value := valueList[0] +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(value), &{{ .GoVariableName }}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, value, &{{ .GoVariableName }}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + return fiber.NewError(fiber.StatusBadRequest, "Header parameter {{ .Name }} is required, but not found") + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + if cookie := c.Cookies("{{ .Name }}"); cookie != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s': %s", "{{ .Name }}", err)) + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + return fiber.NewError(fiber.StatusBadRequest, "Query argument {{ .Name }} is required, but not found") + }{{ end }} +{{ end }} +{{ end }} + return siw.Handler.{{ .GoOperationID }}(c{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl new file mode 100644 index 0000000000..3ba848a34a --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl @@ -0,0 +1,37 @@ +{{- /* + This template generates the HTTP handler and routing for Gin servers. + Input: []OperationDescriptor +*/ -}} + +// 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) { +{{ if . }} + 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, + } +{{ end }} +{{- range . }} + router.{{ .Method }}(options.BaseURL+"{{ pathToGinPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl new file mode 100644 index 0000000000..a2b22df6d6 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Gin servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(c *gin.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(c *gin.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { + c.Status(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl new file mode 100644 index 0000000000..1b150abc7b --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl @@ -0,0 +1,78 @@ +{{- /* + This template generates the receiver interface and handler functions for Gin. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(c *gin.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns a gin.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) gin.HandlerFunc { + return func(c *gin.Context) { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := c.Query("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + c.JSON(http.StatusBadRequest, gin.H{"error": "Query parameter {{ .Name }} is required"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Request.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) + return + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList := c.Request.Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)}) + return + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + c.JSON(http.StatusBadRequest, gin.H{"error": "Header parameter {{ .Name }} is required"}) + return + }{{ end }} +{{ end }} +{{- end }} + si.Handle{{ .GoOperationID }}{{ $.Prefix }}(c{{ if .HasParams }}, params{{ end }}) + } +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl new file mode 100644 index 0000000000..1fb5792ee5 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl @@ -0,0 +1,161 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Gin. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandler func(*gin.Context, error, int) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(c *gin.Context) + +{{ range . }} +// {{ .GoOperationID }} operation middleware +func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c *gin.Context) { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = c.Param("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(c.Param("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, c.Param("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) + return + } +{{- end }} +{{ end }} +{{- if .Security }} +{{- range .Security }} + c.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Request.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) + return + } +{{- else if or .Required .IsPassThrough .IsJSON }} + if paramValue := c.Query("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON: %w", err), http.StatusBadRequest) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandler(c, fmt.Errorf("Query argument {{ .Name }} is required, but not found"), http.StatusBadRequest) + return + }{{ end }} +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := c.Request.Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for {{ .Name }}, got %d", n), http.StatusBadRequest) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter {{ .Name }} is required, but not found"), http.StatusBadRequest) + return + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + { + var cookie string + if cookie, err = c.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{ .Name }}'"), http.StatusBadRequest) + return + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandler(c, fmt.Errorf("Query argument {{ .Name }} is required, but not found"), http.StatusBadRequest) + return + }{{ end }} + } +{{ end }} +{{ end }} + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.{{ .GoOperationID }}(c{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl new file mode 100644 index 0000000000..9d7bcf2121 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl @@ -0,0 +1,57 @@ +{{- /* + This template generates the HTTP handler and routing for Gorilla servers. + Input: []OperationDescriptor +*/ -}} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, GorillaServerOptions{}) +} + +// GorillaServerOptions configures the Gorilla server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +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) + } + } +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, + } +{{ end }} +{{- range . }} + r.HandleFunc(options.BaseURL+"{{ pathToGorillaPattern .Path }}", wrapper.{{ .GoOperationID }}).Methods("{{ .Method }}") +{{- end }} + return r +} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl new file mode 100644 index 0000000000..7a9855b515 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Gorilla servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { + w.WriteHeader(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl new file mode 100644 index 0000000000..b0a24f0fdc --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl @@ -0,0 +1,95 @@ +{{- /* + This template generates the receiver interface and handler functions for Gorilla. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. +type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) + return + }{{ end }} +{{ end }} +{{- end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl new file mode 100644 index 0000000000..395fea4d7b --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl @@ -0,0 +1,169 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Gorilla. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +{{ range . }} +// {{ .GoOperationID }} operation middleware +func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ if .PathParams }} + pathParams := mux.Vars(r) +{{ end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = pathParams["{{ .Name }}"] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(pathParams["{{ .Name }}"]), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, pathParams["{{ .Name }}"], &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{- if .Security }} + ctx := r.Context() +{{- range .Security }} + ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} + r = r.WithContext(ctx) +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := r.Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") + siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) + return + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + { + var cookie *http.Cookie + if cookie, err = r.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie.Value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} + } +{{ end }} +{{ end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl new file mode 100644 index 0000000000..2fa5813b49 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl @@ -0,0 +1,28 @@ +{{- /* + This template generates the HTTP handler and routing for Iris servers. + Input: []OperationDescriptor +*/ -}} + +// IrisServerOptions is the option for iris server. +type IrisServerOptions struct { + BaseURL string + Middlewares []iris.Handler +} + +// 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) { +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + } +{{ end }} +{{- range . }} + router.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToIrisPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} + router.Build() +} diff --git a/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl new file mode 100644 index 0000000000..5b80fa550c --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates the ServerInterface for Iris servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(ctx iris.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. +type Unimplemented struct{} + +{{- range . }} +{{ .SummaryAsComment }} +// ({{ .Method }} {{ .Path }}) +func (_ Unimplemented) {{ .GoOperationID }}(ctx iris.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { + ctx.StatusCode(http.StatusNotImplemented) +} +{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl new file mode 100644 index 0000000000..050076b4a4 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl @@ -0,0 +1,84 @@ +{{- /* + This template generates the receiver interface and handler functions for Iris. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx iris.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an iris.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) iris.Handler { + return func(ctx iris.Context) { +{{- if .HasParams }} + var err error + _ = err + + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := ctx.URLParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString("Query parameter {{ .Name }} is required") + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.Request().URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString(fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + return + } +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + ctx.StatusCode(http.StatusBadRequest) + _, _ = ctx.WriteString("Header parameter {{ .Name }} is required") + return + }{{ end }} +{{ end }} +{{- end }} + si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) + } +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl new file mode 100644 index 0000000000..8c44f3dd10 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl @@ -0,0 +1,160 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods for Iris. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts iris contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface +} + +{{ range . }} +// {{ .GoOperationID }} converts iris context to params. +func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx iris.Context) { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = ctx.Params().Get("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(ctx.Params().Get("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Params().Get("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } +{{- end }} +{{ end }} +{{- if .Security }} +{{- range .Security }} + ctx.Values().Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.Request().URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } +{{- else }} + if paramValue := ctx.URLParam("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString("Query argument {{ .Name }} is required, but not found") + return + }{{ end }} +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := ctx.Request().Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString("Header {{ .Name }} is required, but not found") + return + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + if cookie := ctx.GetCookie("{{ .Name }}"); cookie != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) + return + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) + if err != nil { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + ctx.StatusCode(http.StatusBadRequest) + ctx.WriteString("Cookie {{ .Name }} is required, but not found") + return + }{{ end }} +{{ end }} +{{ end }} + // Invoke the callback with all the unmarshaled arguments + w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/param_types.go.tmpl b/experimental/internal/codegen/templates/files/server/param_types.go.tmpl new file mode 100644 index 0000000000..7b0eb914de --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/param_types.go.tmpl @@ -0,0 +1,24 @@ +{{- /* + This template generates parameter struct types for server operations. + Input: []OperationDescriptor +*/ -}} + +{{ range . }} +{{- if .HasParams }} +// {{ .ParamsTypeName }} defines parameters for {{ .GoOperationID }}. +type {{ .ParamsTypeName }} struct { +{{- range .QueryParams }} + // {{ .Name }} {{ if .Required }}(required){{ else }}(optional){{ end }} + {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} `form:"{{ .Name }}" json:"{{ .Name }}"` +{{- end }} +{{- range .HeaderParams }} + // {{ .Name }} (header{{ if .Required }}, required{{ end }}) + {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} +{{- end }} +{{- range .CookieParams }} + // {{ .Name }} (cookie{{ if .Required }}, required{{ end }}) + {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} +{{- end }} +} +{{ end }} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl new file mode 100644 index 0000000000..47d50ec8bc --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl @@ -0,0 +1,63 @@ +{{- /* + This template generates the HTTP handler and routing for StdHTTP servers. + Input: []OperationDescriptor +*/ -}} + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +// StdHTTPServerOptions configures the StdHTTP server. +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, + }) +} + +// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. +func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{ + BaseURL: baseURL, + BaseRouter: m, + }) +} + +// HandlerWithOptions creates http.Handler with additional options. +func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { + m := options.BaseRouter + + if m == nil { + m = http.NewServeMux() + } + if options.ErrorHandlerFunc == nil { + options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } +{{ if . }} + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, + } +{{ end }} +{{- range . }} + m.HandleFunc("{{ .Method }} "+options.BaseURL+"{{ pathToStdHTTPPattern .Path }}", wrapper.{{ .GoOperationID }}) +{{- end }} + return m +} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl new file mode 100644 index 0000000000..6dc320f8f7 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl @@ -0,0 +1,13 @@ +{{- /* + This template generates the ServerInterface for StdHTTP servers. + Input: []OperationDescriptor +*/ -}} + +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{- range . }} +{{ .SummaryAsComment }} + // ({{ .Method }} {{ .Path }}) + {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl new file mode 100644 index 0000000000..5f6d1fb5d0 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl @@ -0,0 +1,108 @@ +{{- /* + This template generates the receiver interface and handler functions for StdHTTP. + Receiver handlers receive webhook/callback requests — the caller registers them at chosen paths. + Input: ReceiverTemplateData +*/ -}} + +// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. +type {{ .Prefix }}ReceiverInterface interface { +{{- range .Operations }} +{{ .SummaryAsComment }} + // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. + Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) +{{- end }} +} + +// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. +type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler + +{{ range .Operations }} +// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. +// The caller is responsible for registering this handler at the appropriate path. +func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { + if errHandler == nil { + errHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +{{- if .HasParams }} + var err error + _ = err + + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ range .HeaderParams }} + if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) + return + }{{ end }} +{{ end }} +{{- end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range middlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) + }) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl new file mode 100644 index 0000000000..6c74e9c980 --- /dev/null +++ b/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl @@ -0,0 +1,166 @@ +{{- /* + This template generates the ServerInterfaceWrapper that extracts parameters + from HTTP requests and calls the ServerInterface methods. + Input: []OperationDescriptor +*/ -}} + +// ServerInterfaceWrapper converts HTTP requests to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// MiddlewareFunc is a middleware function type. +type MiddlewareFunc func(http.Handler) http.Handler + +{{ range . }} +// {{ .GoOperationID }} operation middleware +func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { +{{- if or .PathParams .HasParams }} + var err error +{{- end }} +{{ range .PathParams }} + // ------------- Path parameter "{{ .Name }}" ------------- + var {{ .GoVariableName }} {{ .TypeDecl }} +{{ if .IsPassThrough }} + {{ .GoVariableName }} = r.PathValue("{{ .Name }}") +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(r.PathValue("{{ .Name }}")), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, r.PathValue("{{ .Name }}"), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{- if .Security }} + ctx := r.Context() +{{- range .Security }} + ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) +{{- end }} + r = r.WithContext(ctx) +{{- end }} +{{ if .HasParams }} + // Parameter object where we will unmarshal all parameters from the context + var params {{ .ParamsTypeName }} +{{ range .QueryParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- +{{- if or .Required .IsPassThrough .IsJSON }} + if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + err = json.Unmarshal([]byte(paramValue), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{ end }} +{{ if .HeaderParams }} + headers := r.Header +{{ range .HeaderParams }} + // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { + var {{ .GoVariableName }} {{ .TypeDecl }} + n := len(valueList) + if n != 1 { + siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) + return + } +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] +{{- end }} +{{- if .IsJSON }} + err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} +{{- if .IsStyled }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } +{{- end }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} + }{{ if .Required }} else { + err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") + siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) + return + }{{ end }} +{{ end }} +{{ end }} +{{ range .CookieParams }} + { + var cookie *http.Cookie + if cookie, err = r.Cookie("{{ .Name }}"); err == nil { +{{- if .IsPassThrough }} + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value +{{- end }} +{{- if .IsJSON }} + var value {{ .TypeDecl }} + decoded, err := url.QueryUnescape(cookie.Value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + err = json.Unmarshal([]byte(decoded), &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} +{{- if .IsStyled }} + var value {{ .TypeDecl }} + err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) + return + } + params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value +{{- end }} + }{{ if .Required }} else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) + return + }{{ end }} + } +{{ end }} +{{ end }} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} +{{ end }} diff --git a/experimental/internal/codegen/templates/files/types/date.tmpl b/experimental/internal/codegen/templates/files/types/date.tmpl new file mode 100644 index 0000000000..1698b09320 --- /dev/null +++ b/experimental/internal/codegen/templates/files/types/date.tmpl @@ -0,0 +1,38 @@ +{{/* Date type for OpenAPI format: date */}} + +const DateFormat = "2006-01-02" + +type Date struct { + time.Time +} + +func (d Date) MarshalJSON() ([]byte, error) { + return json.Marshal(d.Format(DateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var dateStr string + err := json.Unmarshal(data, &dateStr) + if err != nil { + return err + } + parsed, err := time.Parse(DateFormat, dateStr) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +func (d Date) String() string { + return d.Format(DateFormat) +} + +func (d *Date) UnmarshalText(data []byte) error { + parsed, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = parsed + return nil +} diff --git a/experimental/internal/codegen/templates/files/types/email.tmpl b/experimental/internal/codegen/templates/files/types/email.tmpl new file mode 100644 index 0000000000..1f1e5d100a --- /dev/null +++ b/experimental/internal/codegen/templates/files/types/email.tmpl @@ -0,0 +1,43 @@ +{{/* Email type for OpenAPI format: email */}} + +const ( + emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" +) + +var ( + emailRegex = regexp.MustCompile(emailRegexString) +) + +// ErrValidationEmail is the sentinel error returned when an email fails validation +var ErrValidationEmail = errors.New("email: failed to pass regex validation") + +// Email represents an email address. +// It is a string type that must pass regex validation before being marshalled +// to JSON or unmarshalled from JSON. +type Email string + +func (e Email) MarshalJSON() ([]byte, error) { + if !emailRegex.MatchString(string(e)) { + return nil, ErrValidationEmail + } + + return json.Marshal(string(e)) +} + +func (e *Email) UnmarshalJSON(data []byte) error { + if e == nil { + return nil + } + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *e = Email(s) + if !emailRegex.MatchString(s) { + return ErrValidationEmail + } + + return nil +} diff --git a/experimental/internal/codegen/templates/files/types/file.tmpl b/experimental/internal/codegen/templates/files/types/file.tmpl new file mode 100644 index 0000000000..3b853101bb --- /dev/null +++ b/experimental/internal/codegen/templates/files/types/file.tmpl @@ -0,0 +1,64 @@ +{{/* File type for OpenAPI format: binary */}} + +type File struct { + multipart *multipart.FileHeader + data []byte + filename string +} + +func (file *File) InitFromMultipart(header *multipart.FileHeader) { + file.multipart = header + file.data = nil + file.filename = "" +} + +func (file *File) InitFromBytes(data []byte, filename string) { + file.data = data + file.filename = filename + file.multipart = nil +} + +func (file File) MarshalJSON() ([]byte, error) { + b, err := file.Bytes() + if err != nil { + return nil, err + } + return json.Marshal(b) +} + +func (file *File) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &file.data) +} + +func (file File) Bytes() ([]byte, error) { + if file.multipart != nil { + f, err := file.multipart.Open() + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + return io.ReadAll(f) + } + return file.data, nil +} + +func (file File) Reader() (io.ReadCloser, error) { + if file.multipart != nil { + return file.multipart.Open() + } + return io.NopCloser(bytes.NewReader(file.data)), nil +} + +func (file File) Filename() string { + if file.multipart != nil { + return file.multipart.Filename + } + return file.filename +} + +func (file File) FileSize() int64 { + if file.multipart != nil { + return file.multipart.Size + } + return int64(len(file.data)) +} diff --git a/experimental/internal/codegen/templates/files/types/nullable.tmpl b/experimental/internal/codegen/templates/files/types/nullable.tmpl new file mode 100644 index 0000000000..cf75b0910c --- /dev/null +++ b/experimental/internal/codegen/templates/files/types/nullable.tmpl @@ -0,0 +1,104 @@ +{{/* Nullable type for OpenAPI nullable fields - implements three-state semantics: unspecified, null, or value */}} + +// Nullable is a generic type that can distinguish between: +// - Field not provided (unspecified) +// - Field explicitly set to null +// - Field has a value +// +// This is implemented as a map[bool]T where: +// - Empty map: unspecified +// - map[false]T: explicitly null +// - map[true]T: has a value +type Nullable[T any] map[bool]T + +// NewNullableWithValue creates a Nullable with the given value. +func NewNullableWithValue[T any](value T) Nullable[T] { + return Nullable[T]{true: value} +} + +// NewNullNullable creates a Nullable that is explicitly null. +func NewNullNullable[T any]() Nullable[T] { + return Nullable[T]{false: *new(T)} +} + +// Get returns the value if set, or an error if null or unspecified. +func (n Nullable[T]) Get() (T, error) { + if v, ok := n[true]; ok { + return v, nil + } + var zero T + if n.IsNull() { + return zero, ErrNullableIsNull + } + return zero, ErrNullableNotSpecified +} + +// MustGet returns the value or panics if null or unspecified. +func (n Nullable[T]) MustGet() T { + v, err := n.Get() + if err != nil { + panic(err) + } + return v +} + +// Set assigns a value. +func (n *Nullable[T]) Set(value T) { + *n = Nullable[T]{true: value} +} + +// SetNull marks the field as explicitly null. +func (n *Nullable[T]) SetNull() { + *n = Nullable[T]{false: *new(T)} +} + +// SetUnspecified clears the field (as if it was never set). +func (n *Nullable[T]) SetUnspecified() { + *n = nil +} + +// IsNull returns true if the field is explicitly null. +func (n Nullable[T]) IsNull() bool { + if n == nil { + return false + } + _, ok := n[false] + return ok +} + +// IsSpecified returns true if the field was provided (either null or a value). +func (n Nullable[T]) IsSpecified() bool { + return len(n) > 0 +} + +// MarshalJSON implements json.Marshaler. +func (n Nullable[T]) MarshalJSON() ([]byte, error) { + if n.IsNull() { + return []byte("null"), nil + } + if v, ok := n[true]; ok { + return json.Marshal(v) + } + // Unspecified - this shouldn't be called if omitempty is used correctly + return []byte("null"), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *Nullable[T]) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + n.SetNull() + return nil + } + var v T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + n.Set(v) + return nil +} + +// ErrNullableIsNull is returned when trying to get a value from a null Nullable. +var ErrNullableIsNull = errors.New("nullable value is null") + +// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. +var ErrNullableNotSpecified = errors.New("nullable value is not specified") diff --git a/experimental/internal/codegen/templates/files/types/uuid.tmpl b/experimental/internal/codegen/templates/files/types/uuid.tmpl new file mode 100644 index 0000000000..f136f6a150 --- /dev/null +++ b/experimental/internal/codegen/templates/files/types/uuid.tmpl @@ -0,0 +1,3 @@ +{{/* UUID type for OpenAPI format: uuid */}} + +type UUID = uuid.UUID diff --git a/experimental/internal/codegen/templates/funcs.go b/experimental/internal/codegen/templates/funcs.go new file mode 100644 index 0000000000..b790f1702e --- /dev/null +++ b/experimental/internal/codegen/templates/funcs.go @@ -0,0 +1,151 @@ +package templates + +import ( + "regexp" + "strings" + "text/template" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +var titleCaser = cases.Title(language.English) + +// pathParamRE matches OpenAPI path parameters including styled variants. +// Matches: {param}, {param*}, {.param}, {.param*}, {;param}, {;param*}, {?param}, {?param*} +var pathParamRE = regexp.MustCompile(`{[.;?]?([^{}*]+)\*?}`) + +// Funcs returns the template function map for server templates. +func Funcs() template.FuncMap { + return template.FuncMap{ + "pathToStdHTTPPattern": PathToStdHTTPPattern, + "pathToChiPattern": PathToChiPattern, + "pathToEchoPattern": PathToEchoPattern, + "pathToGinPattern": PathToGinPattern, + "pathToGorillaPattern": PathToGorillaPattern, + "pathToFiberPattern": PathToFiberPattern, + "pathToIrisPattern": PathToIrisPattern, + "toGoIdentifier": ToGoIdentifier, + "lower": strings.ToLower, + "title": titleCaser.String, + } +} + +// PathToStdHTTPPattern converts an OpenAPI path template to a Go 1.22+ std http pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// StdHTTP: /users/{user_id}/posts/{post_id} +// Special case: "/" becomes "/{$}" to match only the root path. +func PathToStdHTTPPattern(path string) string { + // https://pkg.go.dev/net/http#hdr-Patterns-ServeMux + // The special wildcard {$} matches only the end of the URL. + if path == "/" { + return "/{$}" + } + return pathParamRE.ReplaceAllString(path, "{$1}") +} + +// PathToChiPattern converts an OpenAPI path template to a Chi-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Chi: /users/{user_id}/posts/{post_id} +func PathToChiPattern(path string) string { + return pathParamRE.ReplaceAllString(path, "{$1}") +} + +// PathToEchoPattern converts an OpenAPI path template to an Echo-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Echo: /users/:user_id/posts/:post_id +func PathToEchoPattern(path string) string { + return pathParamRE.ReplaceAllString(path, ":$1") +} + +// PathToGinPattern converts an OpenAPI path template to a Gin-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Gin: /users/:user_id/posts/:post_id +func PathToGinPattern(path string) string { + return pathParamRE.ReplaceAllString(path, ":$1") +} + +// PathToGorillaPattern converts an OpenAPI path template to a Gorilla Mux-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Gorilla: /users/{user_id}/posts/{post_id} +func PathToGorillaPattern(path string) string { + return pathParamRE.ReplaceAllString(path, "{$1}") +} + +// PathToFiberPattern converts an OpenAPI path template to a Fiber-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Fiber: /users/:user_id/posts/:post_id +func PathToFiberPattern(path string) string { + return pathParamRE.ReplaceAllString(path, ":$1") +} + +// PathToIrisPattern converts an OpenAPI path template to an Iris-compatible pattern. +// OpenAPI: /users/{user_id}/posts/{post_id} +// Iris: /users/:user_id/posts/:post_id +func PathToIrisPattern(path string) string { + return pathParamRE.ReplaceAllString(path, ":$1") +} + +// ToGoIdentifier converts a string to a valid Go identifier. +// This is a simple version for template usage. +func ToGoIdentifier(s string) string { + if s == "" { + return "Empty" + } + + // Replace non-alphanumeric characters with underscores + result := make([]byte, 0, len(s)) + capitalizeNext := true + + for i := 0; i < len(s); i++ { + c := s[i] + if c >= 'a' && c <= 'z' { + if capitalizeNext { + result = append(result, c-32) // uppercase + capitalizeNext = false + } else { + result = append(result, c) + } + } else if c >= 'A' && c <= 'Z' { + result = append(result, c) + capitalizeNext = false + } else if c >= '0' && c <= '9' { + result = append(result, c) + capitalizeNext = false + } else { + // Word separator + capitalizeNext = true + } + } + + if len(result) == 0 { + return "Empty" + } + + // Handle leading digit + if result[0] >= '0' && result[0] <= '9' { + result = append([]byte("N"), result...) + } + + str := string(result) + + // Handle Go keywords + lower := strings.ToLower(str) + if isGoKeyword(lower) { + str = str + "_" + } + + return str +} + +// isGoKeyword returns true if s is a Go keyword. +func isGoKeyword(s string) bool { + keywords := map[string]bool{ + "break": true, "case": true, "chan": true, "const": true, "continue": true, + "default": true, "defer": true, "else": true, "fallthrough": true, "for": true, + "func": true, "go": true, "goto": true, "if": true, "import": true, + "interface": true, "map": true, "package": true, "range": true, "return": true, + "select": true, "struct": true, "switch": true, "type": true, "var": true, + } + return keywords[s] +} diff --git a/experimental/internal/codegen/templates/registry.go b/experimental/internal/codegen/templates/registry.go new file mode 100644 index 0000000000..94ae240769 --- /dev/null +++ b/experimental/internal/codegen/templates/registry.go @@ -0,0 +1,909 @@ +package templates + +// Import represents a Go import with optional alias. +type Import struct { + Path string + Alias string // empty if no alias +} + +// TypeTemplate defines a template for a custom type along with its required imports. +type TypeTemplate struct { + Name string // Type name (e.g., "Email", "Date") + Imports []Import // Required imports for this type + Template string // Template name in embedded FS (e.g., "types/email.tmpl") +} + +// TypeTemplates maps type names to their template definitions. +var TypeTemplates = map[string]TypeTemplate{ + "Email": { + Name: "Email", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "regexp"}, + }, + Template: "types/email.tmpl", + }, + "Date": { + Name: "Date", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "time"}, + }, + Template: "types/date.tmpl", + }, + "UUID": { + Name: "UUID", + Imports: []Import{ + {Path: "github.com/google/uuid"}, + }, + Template: "types/uuid.tmpl", + }, + "File": { + Name: "File", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding/json"}, + {Path: "io"}, + {Path: "mime/multipart"}, + }, + Template: "types/file.tmpl", + }, + "Nullable": { + Name: "Nullable", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "errors"}, + }, + Template: "types/nullable.tmpl", + }, +} + +// ParamTemplate defines a template for a parameter styling/binding function. +type ParamTemplate struct { + Name string // Function name (e.g., "StyleSimpleParam") + Imports []Import // Required imports for this function + Template string // Template name in embedded FS (e.g., "params/style_simple.go.tmpl") +} + +// ParamHelpersTemplate is the template for shared helper functions. +// This is included whenever any param function is used. +var ParamHelpersTemplate = ParamTemplate{ + Name: "helpers", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "net/url"}, + {Path: "reflect"}, + {Path: "sort"}, + {Path: "strconv"}, + {Path: "strings"}, + {Path: "time"}, + {Path: "github.com/google/uuid"}, + }, + Template: "params/helpers.go.tmpl", +} + +// ParamTemplates maps style/explode combinations to their template definitions. +// Keys follow the pattern: "style_{style}" or "style_{style}_explode" for styling, +// and "bind_{style}" or "bind_{style}_explode" for binding. +var ParamTemplates = map[string]ParamTemplate{ + // Style templates (serialization) + "style_simple": { + Name: "StyleSimpleParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_simple.go.tmpl", + }, + "style_simple_explode": { + Name: "StyleSimpleExplodeParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_simple_explode.go.tmpl", + }, + "style_label": { + Name: "StyleLabelParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_label.go.tmpl", + }, + "style_label_explode": { + Name: "StyleLabelExplodeParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_label_explode.go.tmpl", + }, + "style_matrix": { + Name: "StyleMatrixParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_matrix.go.tmpl", + }, + "style_matrix_explode": { + Name: "StyleMatrixExplodeParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_matrix_explode.go.tmpl", + }, + "style_form": { + Name: "StyleFormParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_form.go.tmpl", + }, + "style_form_explode": { + Name: "StyleFormExplodeParam", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding"}, + {Path: "encoding/json"}, + {Path: "errors"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_form_explode.go.tmpl", + }, + "style_spaceDelimited": { + Name: "StyleSpaceDelimitedParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_space_delimited.go.tmpl", + }, + "style_spaceDelimited_explode": { + Name: "StyleSpaceDelimitedExplodeParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_space_delimited_explode.go.tmpl", + }, + "style_pipeDelimited": { + Name: "StylePipeDelimitedParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_pipe_delimited.go.tmpl", + }, + "style_pipeDelimited_explode": { + Name: "StylePipeDelimitedExplodeParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/style_pipe_delimited_explode.go.tmpl", + }, + "style_deepObject": { + Name: "StyleDeepObjectParam", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "sort"}, + {Path: "strconv"}, + {Path: "strings"}, + }, + Template: "params/style_deep_object.go.tmpl", + }, + + // Bind templates (deserialization) + "bind_simple": { + Name: "BindSimpleParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_simple.go.tmpl", + }, + "bind_simple_explode": { + Name: "BindSimpleExplodeParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_simple_explode.go.tmpl", + }, + "bind_label": { + Name: "BindLabelParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_label.go.tmpl", + }, + "bind_label_explode": { + Name: "BindLabelExplodeParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_label_explode.go.tmpl", + }, + "bind_matrix": { + Name: "BindMatrixParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_matrix.go.tmpl", + }, + "bind_matrix_explode": { + Name: "BindMatrixExplodeParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_matrix_explode.go.tmpl", + }, + "bind_form": { + Name: "BindFormParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_form.go.tmpl", + }, + "bind_form_explode": { + Name: "BindFormExplodeParam", + Imports: []Import{ + {Path: "fmt"}, + {Path: "net/url"}, + {Path: "reflect"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/bind_form_explode.go.tmpl", + }, + "bind_spaceDelimited": { + Name: "BindSpaceDelimitedParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_space_delimited.go.tmpl", + }, + "bind_spaceDelimited_explode": { + Name: "BindSpaceDelimitedExplodeParam", + Imports: []Import{ + {Path: "net/url"}, + }, + Template: "params/bind_space_delimited_explode.go.tmpl", + }, + "bind_pipeDelimited": { + Name: "BindPipeDelimitedParam", + Imports: []Import{ + {Path: "encoding"}, + {Path: "fmt"}, + {Path: "reflect"}, + {Path: "strings"}, + }, + Template: "params/bind_pipe_delimited.go.tmpl", + }, + "bind_pipeDelimited_explode": { + Name: "BindPipeDelimitedExplodeParam", + Imports: []Import{ + {Path: "net/url"}, + }, + Template: "params/bind_pipe_delimited_explode.go.tmpl", + }, + "bind_deepObject": { + Name: "BindDeepObjectParam", + Imports: []Import{ + {Path: "errors"}, + {Path: "fmt"}, + {Path: "net/url"}, + {Path: "reflect"}, + {Path: "sort"}, + {Path: "strconv"}, + {Path: "strings"}, + {Path: "time"}, + }, + Template: "params/bind_deep_object.go.tmpl", + }, +} + +// ParamStyleKey returns the registry key for a style/explode combination. +// The prefix should be "style_" for serialization or "bind_" for binding. +func ParamStyleKey(prefix, style string, explode bool) string { + key := prefix + style + if explode { + key += "_explode" + } + return key +} + +// ServerTemplate defines a template for server generation. +type ServerTemplate struct { + Name string // Template name (e.g., "interface", "handler") + Imports []Import // Required imports for this template + Template string // Template path in embedded FS +} + +// ReceiverTemplate defines a template for receiver (webhook/callback) generation. +type ReceiverTemplate struct { + Name string // Template name (e.g., "receiver") + Imports []Import // Required imports for this template + Template string // Template path in embedded FS +} + +// StdHTTPReceiverTemplates contains receiver templates for StdHTTP servers. +var StdHTTPReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "server/stdhttp/receiver.go.tmpl", + }, +} + +// ChiReceiverTemplates contains receiver templates for Chi servers. +var ChiReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "server/chi/receiver.go.tmpl", + }, +} + +// EchoReceiverTemplates contains receiver templates for Echo v5 servers. +var EchoReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/labstack/echo/v5"}, + }, + Template: "server/echo/receiver.go.tmpl", + }, +} + +// EchoV4ReceiverTemplates contains receiver templates for Echo v4 servers. +var EchoV4ReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/labstack/echo/v4"}, + }, + Template: "server/echo-v4/receiver.go.tmpl", + }, +} + +// GinReceiverTemplates contains receiver templates for Gin servers. +var GinReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/gin-gonic/gin"}, + }, + Template: "server/gin/receiver.go.tmpl", + }, +} + +// GorillaReceiverTemplates contains receiver templates for Gorilla servers. +var GorillaReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "server/gorilla/receiver.go.tmpl", + }, +} + +// FiberReceiverTemplates contains receiver templates for Fiber servers. +var FiberReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/gofiber/fiber/v3"}, + }, + Template: "server/fiber/receiver.go.tmpl", + }, +} + +// IrisReceiverTemplates contains receiver templates for Iris servers. +var IrisReceiverTemplates = map[string]ReceiverTemplate{ + "receiver": { + Name: "receiver", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/kataras/iris/v12"}, + }, + Template: "server/iris/receiver.go.tmpl", + }, +} + +// StdHTTPServerTemplates contains templates for StdHTTP server generation. +var StdHTTPServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + }, + Template: "server/stdhttp/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "net/http"}, + }, + Template: "server/stdhttp/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "server/stdhttp/wrapper.go.tmpl", + }, +} + +// ChiServerTemplates contains templates for Chi server generation. +var ChiServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + }, + Template: "server/chi/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/go-chi/chi/v5"}, + }, + Template: "server/chi/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/go-chi/chi/v5"}, + }, + Template: "server/chi/wrapper.go.tmpl", + }, +} + +// EchoServerTemplates contains templates for Echo v5 server generation. +var EchoServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/labstack/echo/v5"}, + }, + Template: "server/echo/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "github.com/labstack/echo/v5"}, + }, + Template: "server/echo/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/labstack/echo/v5"}, + }, + Template: "server/echo/wrapper.go.tmpl", + }, +} + +// EchoV4ServerTemplates contains templates for Echo v4 server generation. +var EchoV4ServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/labstack/echo/v4"}, + }, + Template: "server/echo-v4/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "github.com/labstack/echo/v4"}, + }, + Template: "server/echo-v4/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/labstack/echo/v4"}, + }, + Template: "server/echo-v4/wrapper.go.tmpl", + }, +} + +// GinServerTemplates contains templates for Gin server generation. +var GinServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/gin-gonic/gin"}, + }, + Template: "server/gin/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "github.com/gin-gonic/gin"}, + }, + Template: "server/gin/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/gin-gonic/gin"}, + }, + Template: "server/gin/wrapper.go.tmpl", + }, +} + +// GorillaServerTemplates contains templates for Gorilla server generation. +var GorillaServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + }, + Template: "server/gorilla/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/gorilla/mux"}, + }, + Template: "server/gorilla/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/gorilla/mux"}, + }, + Template: "server/gorilla/wrapper.go.tmpl", + }, +} + +// FiberServerTemplates contains templates for Fiber server generation. +var FiberServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "github.com/gofiber/fiber/v3"}, + }, + Template: "server/fiber/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "github.com/gofiber/fiber/v3"}, + }, + Template: "server/fiber/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/gofiber/fiber/v3"}, + }, + Template: "server/fiber/wrapper.go.tmpl", + }, +} + +// IrisServerTemplates contains templates for Iris server generation. +var IrisServerTemplates = map[string]ServerTemplate{ + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "net/http"}, + {Path: "github.com/kataras/iris/v12"}, + }, + Template: "server/iris/interface.go.tmpl", + }, + "handler": { + Name: "handler", + Imports: []Import{ + {Path: "github.com/kataras/iris/v12"}, + }, + Template: "server/iris/handler.go.tmpl", + }, + "wrapper": { + Name: "wrapper", + Imports: []Import{ + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "github.com/kataras/iris/v12"}, + }, + Template: "server/iris/wrapper.go.tmpl", + }, +} + +// SharedServerTemplates contains templates shared across all server implementations. +var SharedServerTemplates = map[string]ServerTemplate{ + "errors": { + Name: "errors", + Imports: []Import{ + {Path: "fmt"}, + }, + Template: "server/errors.go.tmpl", + }, + "param_types": { + Name: "param_types", + Imports: []Import{}, + Template: "server/param_types.go.tmpl", + }, +} + +// InitiatorTemplate defines a template for initiator (webhook/callback sender) generation. +type InitiatorTemplate struct { + Name string // Template name (e.g., "initiator_base", "initiator_interface") + Imports []Import // Required imports for this template + Template string // Template path in embedded FS +} + +// InitiatorTemplates contains templates for initiator generation. +// These are shared between webhook and callback initiators (parameterized by prefix). +var InitiatorTemplates = map[string]InitiatorTemplate{ + "initiator_base": { + Name: "initiator_base", + Imports: []Import{ + {Path: "context"}, + {Path: "net/http"}, + }, + Template: "initiator/base.go.tmpl", + }, + "initiator_interface": { + Name: "initiator_interface", + Imports: []Import{ + {Path: "context"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "initiator/interface.go.tmpl", + }, + "initiator_methods": { + Name: "initiator_methods", + Imports: []Import{ + {Path: "context"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "initiator/methods.go.tmpl", + }, + "initiator_request_builders": { + Name: "initiator_request_builders", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding/json"}, + {Path: "io"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "initiator/request_builders.go.tmpl", + }, + "initiator_simple": { + Name: "initiator_simple", + Imports: []Import{ + {Path: "context"}, + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "initiator/simple.go.tmpl", + }, +} + +// ClientTemplate defines a template for client generation. +type ClientTemplate struct { + Name string // Template name (e.g., "base", "interface") + Imports []Import // Required imports for this template + Template string // Template path in embedded FS +} + +// ClientTemplates contains templates for client generation. +var ClientTemplates = map[string]ClientTemplate{ + "base": { + Name: "base", + Imports: []Import{ + {Path: "context"}, + {Path: "net/http"}, + {Path: "net/url"}, + {Path: "strings"}, + }, + Template: "client/base.go.tmpl", + }, + "interface": { + Name: "interface", + Imports: []Import{ + {Path: "context"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "client/interface.go.tmpl", + }, + "methods": { + Name: "methods", + Imports: []Import{ + {Path: "context"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "client/methods.go.tmpl", + }, + "request_builders": { + Name: "request_builders", + Imports: []Import{ + {Path: "bytes"}, + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "io"}, + {Path: "net/http"}, + {Path: "net/url"}, + }, + Template: "client/request_builders.go.tmpl", + }, + "simple": { + Name: "simple", + Imports: []Import{ + {Path: "context"}, + {Path: "encoding/json"}, + {Path: "fmt"}, + {Path: "io"}, + {Path: "net/http"}, + }, + Template: "client/simple.go.tmpl", + }, +} diff --git a/experimental/internal/codegen/templates/test/types/date.gen.go b/experimental/internal/codegen/templates/test/types/date.gen.go new file mode 100644 index 0000000000..37c30d3b98 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/date.gen.go @@ -0,0 +1,46 @@ +// Code generated by gentypes. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "time" +) + + +const DateFormat = "2006-01-02" + +type Date struct { + time.Time +} + +func (d Date) MarshalJSON() ([]byte, error) { + return json.Marshal(d.Format(DateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var dateStr string + err := json.Unmarshal(data, &dateStr) + if err != nil { + return err + } + parsed, err := time.Parse(DateFormat, dateStr) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +func (d Date) String() string { + return d.Format(DateFormat) +} + +func (d *Date) UnmarshalText(data []byte) error { + parsed, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = parsed + return nil +} diff --git a/experimental/internal/codegen/templates/test/types/date_test.go b/experimental/internal/codegen/templates/test/types/date_test.go new file mode 100644 index 0000000000..211776522f --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/date_test.go @@ -0,0 +1,65 @@ +package types + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDate_MarshalJSON(t *testing.T) { + testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) + b := struct { + DateField Date `json:"date"` + }{ + DateField: Date{testDate}, + } + jsonBytes, err := json.Marshal(b) + assert.NoError(t, err) + assert.JSONEq(t, `{"date":"2019-04-01"}`, string(jsonBytes)) +} + +func TestDate_UnmarshalJSON(t *testing.T) { + testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) + jsonStr := `{"date":"2019-04-01"}` + b := struct { + DateField Date `json:"date"` + }{} + err := json.Unmarshal([]byte(jsonStr), &b) + assert.NoError(t, err) + assert.Equal(t, testDate, b.DateField.Time) +} + +func TestDate_Stringer(t *testing.T) { + t.Run("nil date", func(t *testing.T) { + var d *Date + assert.Equal(t, "", fmt.Sprintf("%v", d)) + }) + + t.Run("ptr date", func(t *testing.T) { + d := &Date{ + Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), + } + assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d)) + }) + + t.Run("value date", func(t *testing.T) { + d := Date{ + Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), + } + assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d)) + }) +} + +func TestDate_UnmarshalText(t *testing.T) { + testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC) + value := []byte("2022-06-14") + + date := Date{} + err := date.UnmarshalText(value) + + assert.NoError(t, err) + assert.Equal(t, testDate, date.Time) +} diff --git a/experimental/internal/codegen/templates/test/types/email.gen.go b/experimental/internal/codegen/templates/test/types/email.gen.go new file mode 100644 index 0000000000..6db0d58270 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/email.gen.go @@ -0,0 +1,52 @@ +// Code generated by gentypes. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + "regexp" +) + + +const ( + emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" +) + +var ( + emailRegex = regexp.MustCompile(emailRegexString) +) + +// ErrValidationEmail is the sentinel error returned when an email fails validation +var ErrValidationEmail = errors.New("email: failed to pass regex validation") + +// Email represents an email address. +// It is a string type that must pass regex validation before being marshalled +// to JSON or unmarshalled from JSON. +type Email string + +func (e Email) MarshalJSON() ([]byte, error) { + if !emailRegex.MatchString(string(e)) { + return nil, ErrValidationEmail + } + + return json.Marshal(string(e)) +} + +func (e *Email) UnmarshalJSON(data []byte) error { + if e == nil { + return nil + } + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *e = Email(s) + if !emailRegex.MatchString(s) { + return ErrValidationEmail + } + + return nil +} diff --git a/experimental/internal/codegen/templates/test/types/email_test.go b/experimental/internal/codegen/templates/test/types/email_test.go new file mode 100644 index 0000000000..736056b172 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/email_test.go @@ -0,0 +1,176 @@ +package types + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEmail_MarshalJSON_Validation(t *testing.T) { + type requiredEmail struct { + EmailField Email `json:"email"` + } + + testCases := map[string]struct { + email Email + expectedJSON []byte + expectedError error + }{ + "it should succeed marshalling a valid email and return valid JSON populated with the email": { + email: Email("validemail@openapicodegen.com"), + expectedJSON: []byte(`{"email":"validemail@openapicodegen.com"}`), + expectedError: nil, + }, + "it should fail marshalling an invalid email and return a validation error": { + email: Email("invalidemail"), + expectedJSON: nil, + expectedError: ErrValidationEmail, + }, + "it should fail marshalling an empty email and return a validation error": { + email: Email(""), + expectedJSON: nil, + expectedError: ErrValidationEmail, + }, + } + + for name, tc := range testCases { + tc := tc + t.Run(name, func(t *testing.T) { + t.Parallel() + + jsonBytes, err := json.Marshal(requiredEmail{EmailField: tc.email}) + + if tc.expectedError != nil { + assert.ErrorIs(t, err, tc.expectedError) + } else { + assert.JSONEq(t, string(tc.expectedJSON), string(jsonBytes)) + } + }) + } +} + +func TestEmail_UnmarshalJSON_RequiredEmail_Validation(t *testing.T) { + type requiredEmail struct { + EmailField Email `json:"email"` + } + + requiredEmailTestCases := map[string]struct { + jsonStr string + expectedEmail Email + expectedError error + }{ + "it should succeed validating a valid email during the unmarshal process": { + jsonStr: `{"email":"gaben@valvesoftware.com"}`, + expectedError: nil, + expectedEmail: func() Email { + e := Email("gaben@valvesoftware.com") + return e + }(), + }, + "it should fail validating an invalid email": { + jsonStr: `{"email":"not-an-email"}`, + expectedError: ErrValidationEmail, + expectedEmail: func() Email { + e := Email("not-an-email") + return e + }(), + }, + "it should fail validating an empty email": { + jsonStr: `{"email":""}`, + expectedEmail: func() Email { + e := Email("") + return e + }(), + expectedError: ErrValidationEmail, + }, + "it should fail validating a null email": { + jsonStr: `{"email":null}`, + expectedEmail: func() Email { + e := Email("") + return e + }(), + expectedError: ErrValidationEmail, + }, + } + + for name, tc := range requiredEmailTestCases { + tc := tc + t.Run(name, func(t *testing.T) { + t.Parallel() + + b := requiredEmail{} + err := json.Unmarshal([]byte(tc.jsonStr), &b) + assert.Equal(t, tc.expectedEmail, b.EmailField) + assert.ErrorIs(t, err, tc.expectedError) + }) + } + +} + +func TestEmail_UnmarshalJSON_NullableEmail_Validation(t *testing.T) { + + type nullableEmail struct { + EmailField *Email `json:"email,omitempty"` + } + + nullableEmailTestCases := map[string]struct { + body nullableEmail + jsonStr string + expectedEmail *Email + expectedError error + }{ + "it should succeed validating a valid email during the unmarshal process": { + body: nullableEmail{}, + jsonStr: `{"email":"gaben@valvesoftware.com"}`, + expectedError: nil, + expectedEmail: func() *Email { + e := Email("gaben@valvesoftware.com") + return &e + }(), + }, + "it should fail validating an invalid email": { + body: nullableEmail{}, + jsonStr: `{"email":"not-an-email"}`, + expectedError: ErrValidationEmail, + expectedEmail: func() *Email { + e := Email("not-an-email") + return &e + }(), + }, + "it should fail validating an empty email": { + body: nullableEmail{}, + jsonStr: `{"email":""}`, + expectedError: ErrValidationEmail, + expectedEmail: func() *Email { + e := Email("") + return &e + }(), + }, + "it should succeed validating a null email": { + body: nullableEmail{}, + jsonStr: `{"email":null}`, + expectedEmail: nil, + expectedError: nil, + }, + "it should succeed validating a missing email": { + body: nullableEmail{}, + jsonStr: `{}`, + expectedEmail: nil, + expectedError: nil, + }, + } + + for name, tc := range nullableEmailTestCases { + tc := tc + t.Run(name, func(t *testing.T) { + t.Parallel() + + err := json.Unmarshal([]byte(tc.jsonStr), &tc.body) + assert.Equal(t, tc.expectedEmail, tc.body.EmailField) + if tc.expectedError != nil { + assert.ErrorIs(t, err, tc.expectedError) + } + }) + } +} diff --git a/experimental/internal/codegen/templates/test/types/file.gen.go b/experimental/internal/codegen/templates/test/types/file.gen.go new file mode 100644 index 0000000000..391c94a9da --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/file.gen.go @@ -0,0 +1,74 @@ +// Code generated by gentypes. DO NOT EDIT. + +package types + +import ( + "bytes" + "encoding/json" + "io" + "mime/multipart" +) + + +type File struct { + multipart *multipart.FileHeader + data []byte + filename string +} + +func (file *File) InitFromMultipart(header *multipart.FileHeader) { + file.multipart = header + file.data = nil + file.filename = "" +} + +func (file *File) InitFromBytes(data []byte, filename string) { + file.data = data + file.filename = filename + file.multipart = nil +} + +func (file File) MarshalJSON() ([]byte, error) { + b, err := file.Bytes() + if err != nil { + return nil, err + } + return json.Marshal(b) +} + +func (file *File) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &file.data) +} + +func (file File) Bytes() ([]byte, error) { + if file.multipart != nil { + f, err := file.multipart.Open() + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + return io.ReadAll(f) + } + return file.data, nil +} + +func (file File) Reader() (io.ReadCloser, error) { + if file.multipart != nil { + return file.multipart.Open() + } + return io.NopCloser(bytes.NewReader(file.data)), nil +} + +func (file File) Filename() string { + if file.multipart != nil { + return file.multipart.Filename + } + return file.filename +} + +func (file File) FileSize() int64 { + if file.multipart != nil { + return file.multipart.Size + } + return int64(len(file.data)) +} diff --git a/experimental/internal/codegen/templates/test/types/file_test.go b/experimental/internal/codegen/templates/test/types/file_test.go new file mode 100644 index 0000000000..fb4ce98ae1 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/file_test.go @@ -0,0 +1,54 @@ +package types + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var _ json.Marshaler = (*File)(nil) +var _ json.Unmarshaler = (*File)(nil) + +func TestFileJSON(t *testing.T) { + type Object struct { + BinaryField File `json:"binary_field"` + } + + // Check whether we encode JSON properly. + var o Object + o.BinaryField.InitFromBytes([]byte("hello"), "") + buf, err := json.Marshal(o) + require.NoError(t, err) + t.Log(string(buf)) + + // Decode the same object back into File, ensure result is correct. + var o2 Object + err = json.Unmarshal(buf, &o2) + require.NoError(t, err) + o2Bytes, err := o2.BinaryField.Bytes() + require.NoError(t, err) + assert.Equal(t, []byte("hello"), o2Bytes) + + // Ensure it also works via pointer. + type Object2 struct { + BinaryFieldPtr *File `json:"binary_field"` + } + + var o3 Object2 + var f File + f.InitFromBytes([]byte("hello"), "") + o3.BinaryFieldPtr = &f + buf, err = json.Marshal(o) + require.NoError(t, err) + t.Log(string(buf)) + + var o4 Object2 + err = json.Unmarshal(buf, &o4) + require.NoError(t, err) + o4Bytes, err := o4.BinaryFieldPtr.Bytes() + require.NoError(t, err) + assert.Equal(t, []byte("hello"), o4Bytes) + +} diff --git a/experimental/internal/codegen/templates/test/types/generate.go b/experimental/internal/codegen/templates/test/types/generate.go new file mode 100644 index 0000000000..bab32084c7 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/generate.go @@ -0,0 +1,3 @@ +package types + +//go:generate go run ./gentypes -package types -output . Email Date UUID File diff --git a/experimental/internal/codegen/templates/test/types/gentypes/main.go b/experimental/internal/codegen/templates/test/types/gentypes/main.go new file mode 100644 index 0000000000..c22eee2751 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/gentypes/main.go @@ -0,0 +1,109 @@ +// gentypes generates Go type files from templates. +// Usage: gentypes -package -output

[types...] +// +// Example: +// +// //go:generate gentypes -package types -output . Email Date UUID File +package main + +import ( + "bytes" + "flag" + "fmt" + "os" + "path/filepath" + "strings" + "text/template" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" +) + +func main() { + packageName := flag.String("package", "", "Go package name for generated files") + outputDir := flag.String("output", ".", "output directory for generated files") + flag.Parse() + + if *packageName == "" { + fmt.Fprintln(os.Stderr, "error: -package is required") + os.Exit(1) + } + + typeNames := flag.Args() + if len(typeNames) == 0 { + fmt.Fprintln(os.Stderr, "error: at least one type name required") + fmt.Fprintln(os.Stderr, "available types: Email, Date, UUID, File") + os.Exit(1) + } + + for _, typeName := range typeNames { + if err := generateType(*packageName, *outputDir, typeName); err != nil { + fmt.Fprintf(os.Stderr, "error generating %s: %v\n", typeName, err) + os.Exit(1) + } + } +} + +func generateType(packageName, outputDir, typeName string) error { + tt, ok := templates.TypeTemplates[typeName] + if !ok { + return fmt.Errorf("unknown type: %s", typeName) + } + + // Read template content + tmplPath := "files/" + tt.Template + tmplContent, err := templates.TemplateFS.ReadFile(tmplPath) + if err != nil { + return fmt.Errorf("reading template %s: %w", tmplPath, err) + } + + // Parse and execute template (in case it has any directives) + tmpl, err := template.New(typeName).Parse(string(tmplContent)) + if err != nil { + return fmt.Errorf("parsing template: %w", err) + } + + var body bytes.Buffer + if err := tmpl.Execute(&body, nil); err != nil { + return fmt.Errorf("executing template: %w", err) + } + + // Build the output file + var out bytes.Buffer + + // Package declaration + fmt.Fprintf(&out, "// Code generated by gentypes. DO NOT EDIT.\n\n") + fmt.Fprintf(&out, "package %s\n", packageName) + + // Imports + if len(tt.Imports) > 0 { + out.WriteString("\nimport (\n") + for _, imp := range tt.Imports { + if imp.Alias != "" { + fmt.Fprintf(&out, "\t%s %q\n", imp.Alias, imp.Path) + } else { + fmt.Fprintf(&out, "\t%q\n", imp.Path) + } + } + out.WriteString(")\n") + } + + // Template body (skip the leading template comment if present) + bodyStr := body.String() + if strings.HasPrefix(bodyStr, "{{/*") { + // Skip the comment line + if idx := strings.Index(bodyStr, "*/}}"); idx != -1 { + bodyStr = bodyStr[idx+4:] + } + } + out.WriteString(bodyStr) + + // Write output file + filename := strings.ToLower(typeName) + ".gen.go" + outputPath := filepath.Join(outputDir, filename) + if err := os.WriteFile(outputPath, out.Bytes(), 0644); err != nil { + return fmt.Errorf("writing %s: %w", outputPath, err) + } + + fmt.Printf("generated %s\n", outputPath) + return nil +} diff --git a/experimental/internal/codegen/templates/test/types/uuid.gen.go b/experimental/internal/codegen/templates/test/types/uuid.gen.go new file mode 100644 index 0000000000..f1c45b3c36 --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/uuid.gen.go @@ -0,0 +1,10 @@ +// Code generated by gentypes. DO NOT EDIT. + +package types + +import ( + "github.com/google/uuid" +) + + +type UUID = uuid.UUID diff --git a/experimental/internal/codegen/templates/test/types/uuid_test.go b/experimental/internal/codegen/templates/test/types/uuid_test.go new file mode 100644 index 0000000000..bb62040b6c --- /dev/null +++ b/experimental/internal/codegen/templates/test/types/uuid_test.go @@ -0,0 +1,53 @@ +package types + +import ( + "encoding/json" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +func TestUUID_MarshalJSON_Zero(t *testing.T) { + var testUUID UUID + b := struct { + UUIDField UUID `json:"uuid"` + }{ + UUIDField: testUUID, + } + marshaled, err := json.Marshal(b) + assert.NoError(t, err) + assert.JSONEq(t, `{"uuid":"00000000-0000-0000-0000-000000000000"}`, string(marshaled)) +} + +func TestUUID_MarshalJSON_Pass(t *testing.T) { + testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002") + b := struct { + UUIDField UUID `json:"uuid"` + }{ + UUIDField: testUUID, + } + jsonBytes, err := json.Marshal(b) + assert.NoError(t, err) + assert.JSONEq(t, `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}`, string(jsonBytes)) +} + +func TestUUID_UnmarshalJSON_Fail(t *testing.T) { + jsonStr := `{"uuid":"this-is-not-a-uuid"}` + b := struct { + UUIDField UUID `json:"uuid"` + }{} + err := json.Unmarshal([]byte(jsonStr), &b) + assert.Error(t, err) +} + +func TestUUID_UnmarshalJSON_Pass(t *testing.T) { + testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002") + jsonStr := `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}` + b := struct { + UUIDField UUID `json:"uuid"` + }{} + err := json.Unmarshal([]byte(jsonStr), &b) + assert.NoError(t, err) + assert.Equal(t, testUUID, b.UUIDField) +} diff --git a/experimental/internal/codegen/test/comprehensive/doc.go b/experimental/internal/codegen/test/comprehensive/doc.go new file mode 100644 index 0000000000..658e592917 --- /dev/null +++ b/experimental/internal/codegen/test/comprehensive/doc.go @@ -0,0 +1,3 @@ +package comprehensive + +//go:generate go run ../../../../cmd/oapi-codegen -package output -output output/comprehensive.gen.go ../files/comprehensive.yaml diff --git a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go new file mode 100644 index 0000000000..633aa2dbe7 --- /dev/null +++ b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go @@ -0,0 +1,2098 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "regexp" + "strings" + "sync" + "time" + + "github.com/google/uuid" +) + +// #/components/schemas/AllTypesRequired +type AllTypesRequired struct { + IntField int `json:"intField" form:"intField"` + Int32Field int32 `json:"int32Field" form:"int32Field"` + Int64Field int64 `json:"int64Field" form:"int64Field"` + FloatField float32 `json:"floatField" form:"floatField"` + DoubleField float64 `json:"doubleField" form:"doubleField"` + NumberField float32 `json:"numberField" form:"numberField"` + StringField string `json:"stringField" form:"stringField"` + BoolField bool `json:"boolField" form:"boolField"` + DateField Date `json:"dateField" form:"dateField"` + DateTimeField time.Time `json:"dateTimeField" form:"dateTimeField"` + UUIDField UUID `json:"uuidField" form:"uuidField"` + EmailField Email `json:"emailField" form:"emailField"` + URIField string `json:"uriField" form:"uriField"` + HostnameField string `json:"hostnameField" form:"hostnameField"` + Ipv4Field string `json:"ipv4Field" form:"ipv4Field"` + Ipv6Field string `json:"ipv6Field" form:"ipv6Field"` + ByteField []byte `json:"byteField" form:"byteField"` + BinaryField File `json:"binaryField" form:"binaryField"` + PasswordField string `json:"passwordField" form:"passwordField"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllTypesRequired) ApplyDefaults() { +} + +// #/components/schemas/AllTypesOptional +type AllTypesOptional struct { + IntField *int `json:"intField,omitempty" form:"intField,omitempty"` + Int32Field *int32 `json:"int32Field,omitempty" form:"int32Field,omitempty"` + Int64Field *int64 `json:"int64Field,omitempty" form:"int64Field,omitempty"` + FloatField *float32 `json:"floatField,omitempty" form:"floatField,omitempty"` + DoubleField *float64 `json:"doubleField,omitempty" form:"doubleField,omitempty"` + NumberField *float32 `json:"numberField,omitempty" form:"numberField,omitempty"` + StringField *string `json:"stringField,omitempty" form:"stringField,omitempty"` + BoolField *bool `json:"boolField,omitempty" form:"boolField,omitempty"` + DateField *Date `json:"dateField,omitempty" form:"dateField,omitempty"` + DateTimeField *time.Time `json:"dateTimeField,omitempty" form:"dateTimeField,omitempty"` + UUIDField *UUID `json:"uuidField,omitempty" form:"uuidField,omitempty"` + EmailField *Email `json:"emailField,omitempty" form:"emailField,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllTypesOptional) ApplyDefaults() { +} + +// #/components/schemas/NullableRequired +type NullableRequired struct { + NullableString Nullable[string] `json:"nullableString" form:"nullableString"` + NullableInt Nullable[int] `json:"nullableInt" form:"nullableInt"` + NullableObject Nullable[NullableRequiredNullableObject] `json:"nullableObject" form:"nullableObject"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NullableRequired) ApplyDefaults() { +} + +// #/components/schemas/NullableRequired/properties/nullableObject +type NullableRequiredNullableObject struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NullableRequiredNullableObject) ApplyDefaults() { +} + +// #/components/schemas/NullableOptional +type NullableOptional struct { + NullableString Nullable[string] `json:"nullableString,omitempty" form:"nullableString,omitempty"` + NullableInt Nullable[int] `json:"nullableInt,omitempty" form:"nullableInt,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NullableOptional) ApplyDefaults() { +} + +// #/components/schemas/ArrayTypes +type ArrayTypes struct { + StringArray []string `json:"stringArray,omitempty" form:"stringArray,omitempty"` + IntArray []int `json:"intArray,omitempty" form:"intArray,omitempty"` + ObjectArray []SimpleObject `json:"objectArray,omitempty" form:"objectArray,omitempty"` + InlineObjectArray []ArrayTypesInlineObjectArrayItem `json:"inlineObjectArray,omitempty" form:"inlineObjectArray,omitempty"` + NestedArray [][]string `json:"nestedArray,omitempty" form:"nestedArray,omitempty"` + NullableArray []string `json:"nullableArray,omitempty" form:"nullableArray,omitempty"` + ArrayWithConstraints []string `json:"arrayWithConstraints,omitempty" form:"arrayWithConstraints,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ArrayTypes) ApplyDefaults() { +} + +// #/components/schemas/ArrayTypes/properties/objectArray +type ArrayTypesObjectArray = []SimpleObject + +// #/components/schemas/ArrayTypes/properties/inlineObjectArray +type ArrayTypesInlineObjectArray = []ArrayTypesInlineObjectArrayItem + +// #/components/schemas/ArrayTypes/properties/inlineObjectArray/items +type ArrayTypesInlineObjectArrayItem struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ArrayTypesInlineObjectArrayItem) ApplyDefaults() { +} + +// #/components/schemas/SimpleObject +type SimpleObject struct { + ID int `json:"id" form:"id"` + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *SimpleObject) ApplyDefaults() { +} + +// #/components/schemas/NestedObject +type NestedObject struct { + Outer *NestedObjectOuter `json:"outer,omitempty" form:"outer,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NestedObject) ApplyDefaults() { + if s.Outer != nil { + s.Outer.ApplyDefaults() + } +} + +// #/components/schemas/NestedObject/properties/outer +type NestedObjectOuter struct { + Inner *NestedObjectOuterInner `json:"inner,omitempty" form:"inner,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NestedObjectOuter) ApplyDefaults() { + if s.Inner != nil { + s.Inner.ApplyDefaults() + } +} + +// #/components/schemas/NestedObject/properties/outer/properties/inner +type NestedObjectOuterInner struct { + Value *string `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NestedObjectOuterInner) ApplyDefaults() { +} + +// #/components/schemas/AdditionalPropsAny +type AdditionalPropsAny = map[string]any + +// #/components/schemas/AdditionalPropsNone +type AdditionalPropsNone struct { + Known *string `json:"known,omitempty" form:"known,omitempty"` + AdditionalProperties map[string]any `json:"-"` +} + +func (s AdditionalPropsNone) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if s.Known != nil { + result["known"] = s.Known + } + + // Add additional properties + for k, v := range s.AdditionalProperties { + result[k] = v + } + + return json.Marshal(result) +} + +func (s *AdditionalPropsNone) UnmarshalJSON(data []byte) error { + // Known fields + knownFields := map[string]bool{ + "known": true, + } + + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["known"]; ok { + var val string + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.Known = &val + } + + // Collect additional properties + s.AdditionalProperties = make(map[string]any) + for k, v := range raw { + if !knownFields[k] { + var val any + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.AdditionalProperties[k] = val + } + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AdditionalPropsNone) ApplyDefaults() { +} + +// #/components/schemas/AdditionalPropsTyped +type AdditionalPropsTyped = map[string]int + +// #/components/schemas/AdditionalPropsObject +type AdditionalPropsObject = map[string]any + +// #/components/schemas/AdditionalPropsWithProps +type AdditionalPropsWithProps struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + AdditionalProperties map[string]string `json:"-"` +} + +func (s AdditionalPropsWithProps) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if s.ID != nil { + result["id"] = s.ID + } + + // Add additional properties + for k, v := range s.AdditionalProperties { + result[k] = v + } + + return json.Marshal(result) +} + +func (s *AdditionalPropsWithProps) UnmarshalJSON(data []byte) error { + // Known fields + knownFields := map[string]bool{ + "id": true, + } + + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["id"]; ok { + var val int + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.ID = &val + } + + // Collect additional properties + s.AdditionalProperties = make(map[string]string) + for k, v := range raw { + if !knownFields[k] { + var val string + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.AdditionalProperties[k] = val + } + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AdditionalPropsWithProps) ApplyDefaults() { +} + +// #/components/schemas/StringEnum +type StringEnum string + +const ( + StringEnum_value1 StringEnum = "value1" + StringEnum_value2 StringEnum = "value2" + StringEnum_value3 StringEnum = "value3" +) + +// #/components/schemas/IntegerEnum +type IntegerEnum int + +const ( + IntegerEnum_N1 IntegerEnum = 1 + IntegerEnum_N2 IntegerEnum = 2 + IntegerEnum_N3 IntegerEnum = 3 +) + +// #/components/schemas/ObjectWithEnum +type ObjectWithEnum struct { + Status *string `json:"status,omitempty" form:"status,omitempty"` + Priority *int `json:"priority,omitempty" form:"priority,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithEnum) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithEnum/properties/status +type ObjectWithEnumStatus string + +const ( + ObjectWithEnumStatus_pending ObjectWithEnumStatus = "pending" + ObjectWithEnumStatus_active ObjectWithEnumStatus = "active" + ObjectWithEnumStatus_completed ObjectWithEnumStatus = "completed" +) + +// #/components/schemas/ObjectWithEnum/properties/priority +type ObjectWithEnumPriority int + +const ( + ObjectWithEnumPriority_N1 ObjectWithEnumPriority = 1 + ObjectWithEnumPriority_N2 ObjectWithEnumPriority = 2 + ObjectWithEnumPriority_N3 ObjectWithEnumPriority = 3 +) + +// #/components/schemas/InlineEnumInProperty +type InlineEnumInProperty struct { + InlineStatus *string `json:"inlineStatus,omitempty" form:"inlineStatus,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *InlineEnumInProperty) ApplyDefaults() { +} + +// #/components/schemas/InlineEnumInProperty/properties/inlineStatus +type InlineEnumInPropertyInlineStatus string + +const ( + InlineEnumInPropertyInlineStatus_on InlineEnumInPropertyInlineStatus = "on" + InlineEnumInPropertyInlineStatus_off InlineEnumInPropertyInlineStatus = "off" +) + +// #/components/schemas/BaseProperties +type BaseProperties struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *BaseProperties) ApplyDefaults() { +} + +// #/components/schemas/ExtendedObject +type ExtendedObject struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Name string `json:"name" form:"name"` + Description *string `json:"description,omitempty" form:"description,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ExtendedObject) ApplyDefaults() { +} + +// #/components/schemas/DeepInheritance +type DeepInheritance struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Name string `json:"name" form:"name"` + Description *string `json:"description,omitempty" form:"description,omitempty"` + Extra *string `json:"extra,omitempty" form:"extra,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DeepInheritance) ApplyDefaults() { +} + +// #/components/schemas/AllOfMultipleRefs +type AllOfMultipleRefs struct { + ID int `json:"id" form:"id"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Name *string `json:"name,omitempty" form:"name,omitempty"` + Merged *bool `json:"merged,omitempty" form:"merged,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfMultipleRefs) ApplyDefaults() { +} + +// #/components/schemas/AllOfInlineOnly +type AllOfInlineOnly struct { + First *string `json:"first,omitempty" form:"first,omitempty"` + Second *int `json:"second,omitempty" form:"second,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfInlineOnly) ApplyDefaults() { +} + +// #/components/schemas/AnyOfPrimitives +type AnyOfPrimitives struct { + String0 *string + Int1 *int +} + +func (u AnyOfPrimitives) MarshalJSON() ([]byte, error) { + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.Int1 != nil { + return json.Marshal(u.Int1) + } + return []byte("null"), nil +} + +func (u *AnyOfPrimitives) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 int + if err := json.Unmarshal(data, &v1); err == nil { + u.Int1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AnyOfPrimitives) ApplyDefaults() { +} + +// #/components/schemas/AnyOfObjects +type AnyOfObjects struct { + SimpleObject *SimpleObject + BaseProperties *BaseProperties +} + +func (u AnyOfObjects) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.SimpleObject != nil { + data, err := json.Marshal(u.SimpleObject) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.BaseProperties != nil { + data, err := json.Marshal(u.BaseProperties) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *AnyOfObjects) UnmarshalJSON(data []byte) error { + var v0 SimpleObject + if err := json.Unmarshal(data, &v0); err == nil { + u.SimpleObject = &v0 + } + + var v1 BaseProperties + if err := json.Unmarshal(data, &v1); err == nil { + u.BaseProperties = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AnyOfObjects) ApplyDefaults() { + if u.SimpleObject != nil { + u.SimpleObject.ApplyDefaults() + } + if u.BaseProperties != nil { + u.BaseProperties.ApplyDefaults() + } +} + +// #/components/schemas/AnyOfMixed +type AnyOfMixed struct { + String0 *string + SimpleObject *SimpleObject + AnyOfMixedAnyOf2 *AnyOfMixedAnyOf2 +} + +func (u AnyOfMixed) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.SimpleObject != nil { + data, err := json.Marshal(u.SimpleObject) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.AnyOfMixedAnyOf2 != nil { + data, err := json.Marshal(u.AnyOfMixedAnyOf2) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *AnyOfMixed) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 SimpleObject + if err := json.Unmarshal(data, &v1); err == nil { + u.SimpleObject = &v1 + } + + var v2 AnyOfMixedAnyOf2 + if err := json.Unmarshal(data, &v2); err == nil { + u.AnyOfMixedAnyOf2 = &v2 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AnyOfMixed) ApplyDefaults() { + if u.SimpleObject != nil { + u.SimpleObject.ApplyDefaults() + } + if u.AnyOfMixedAnyOf2 != nil { + u.AnyOfMixedAnyOf2.ApplyDefaults() + } +} + +// #/components/schemas/AnyOfMixed/anyOf/2 +type AnyOfMixedAnyOf2 struct { + Inline *bool `json:"inline,omitempty" form:"inline,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AnyOfMixedAnyOf2) ApplyDefaults() { +} + +// #/components/schemas/AnyOfNullable +type AnyOfNullable struct { + String0 *string + Any1 *any +} + +func (u AnyOfNullable) MarshalJSON() ([]byte, error) { + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.Any1 != nil { + return json.Marshal(u.Any1) + } + return []byte("null"), nil +} + +func (u *AnyOfNullable) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 any + if err := json.Unmarshal(data, &v1); err == nil { + u.Any1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AnyOfNullable) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithAnyOfProperty +type ObjectWithAnyOfProperty struct { + Value *ObjectWithAnyOfPropertyValue `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithAnyOfProperty) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithAnyOfProperty/properties/value +type ObjectWithAnyOfPropertyValue struct { + String0 *string + Int1 *int + Bool2 *bool +} + +func (u ObjectWithAnyOfPropertyValue) MarshalJSON() ([]byte, error) { + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.Int1 != nil { + return json.Marshal(u.Int1) + } + if u.Bool2 != nil { + return json.Marshal(u.Bool2) + } + return []byte("null"), nil +} + +func (u *ObjectWithAnyOfPropertyValue) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 int + if err := json.Unmarshal(data, &v1); err == nil { + u.Int1 = &v1 + } + + var v2 bool + if err := json.Unmarshal(data, &v2); err == nil { + u.Bool2 = &v2 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ObjectWithAnyOfPropertyValue) ApplyDefaults() { +} + +// #/components/schemas/ArrayOfAnyOf +type ArrayOfAnyOf = []ArrayOfAnyOfItem + +// #/components/schemas/ArrayOfAnyOf/items +type ArrayOfAnyOfItem struct { + SimpleObject *SimpleObject + BaseProperties *BaseProperties +} + +func (u ArrayOfAnyOfItem) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.SimpleObject != nil { + data, err := json.Marshal(u.SimpleObject) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.BaseProperties != nil { + data, err := json.Marshal(u.BaseProperties) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *ArrayOfAnyOfItem) UnmarshalJSON(data []byte) error { + var v0 SimpleObject + if err := json.Unmarshal(data, &v0); err == nil { + u.SimpleObject = &v0 + } + + var v1 BaseProperties + if err := json.Unmarshal(data, &v1); err == nil { + u.BaseProperties = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ArrayOfAnyOfItem) ApplyDefaults() { + if u.SimpleObject != nil { + u.SimpleObject.ApplyDefaults() + } + if u.BaseProperties != nil { + u.BaseProperties.ApplyDefaults() + } +} + +// #/components/schemas/OneOfSimple +type OneOfSimple struct { + SimpleObject *SimpleObject + BaseProperties *BaseProperties +} + +func (u OneOfSimple) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.SimpleObject != nil { + count++ + data, err = json.Marshal(u.SimpleObject) + if err != nil { + return nil, err + } + } + if u.BaseProperties != nil { + count++ + data, err = json.Marshal(u.BaseProperties) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfSimple: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfSimple) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 SimpleObject + if err := json.Unmarshal(data, &v0); err == nil { + u.SimpleObject = &v0 + successCount++ + } + + var v1 BaseProperties + if err := json.Unmarshal(data, &v1); err == nil { + u.BaseProperties = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfSimple: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfSimple) ApplyDefaults() { + if u.SimpleObject != nil { + u.SimpleObject.ApplyDefaults() + } + if u.BaseProperties != nil { + u.BaseProperties.ApplyDefaults() + } +} + +// #/components/schemas/OneOfWithDiscriminator +type OneOfWithDiscriminator struct { + Cat *Cat + Dog *Dog +} + +func (u OneOfWithDiscriminator) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.Cat != nil { + count++ + data, err = json.Marshal(u.Cat) + if err != nil { + return nil, err + } + } + if u.Dog != nil { + count++ + data, err = json.Marshal(u.Dog) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfWithDiscriminator: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfWithDiscriminator) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 Cat + if err := json.Unmarshal(data, &v0); err == nil { + u.Cat = &v0 + successCount++ + } + + var v1 Dog + if err := json.Unmarshal(data, &v1); err == nil { + u.Dog = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfWithDiscriminator: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfWithDiscriminator) ApplyDefaults() { + if u.Cat != nil { + u.Cat.ApplyDefaults() + } + if u.Dog != nil { + u.Dog.ApplyDefaults() + } +} + +// #/components/schemas/OneOfWithDiscriminatorMapping +type OneOfWithDiscriminatorMapping struct { + Cat *Cat + Dog *Dog +} + +func (u OneOfWithDiscriminatorMapping) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.Cat != nil { + count++ + data, err = json.Marshal(u.Cat) + if err != nil { + return nil, err + } + } + if u.Dog != nil { + count++ + data, err = json.Marshal(u.Dog) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfWithDiscriminatorMapping: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfWithDiscriminatorMapping) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 Cat + if err := json.Unmarshal(data, &v0); err == nil { + u.Cat = &v0 + successCount++ + } + + var v1 Dog + if err := json.Unmarshal(data, &v1); err == nil { + u.Dog = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfWithDiscriminatorMapping: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfWithDiscriminatorMapping) ApplyDefaults() { + if u.Cat != nil { + u.Cat.ApplyDefaults() + } + if u.Dog != nil { + u.Dog.ApplyDefaults() + } +} + +// #/components/schemas/Cat +type Cat struct { + PetType string `json:"petType" form:"petType"` + Meow string `json:"meow" form:"meow"` + WhiskerLength *float32 `json:"whiskerLength,omitempty" form:"whiskerLength,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Cat) ApplyDefaults() { +} + +// #/components/schemas/Dog +type Dog struct { + PetType string `json:"petType" form:"petType"` + Bark string `json:"bark" form:"bark"` + TailLength *float32 `json:"tailLength,omitempty" form:"tailLength,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Dog) ApplyDefaults() { +} + +// #/components/schemas/OneOfInline +type OneOfInline struct { + OneOfInlineOneOf0 *OneOfInlineOneOf0 + OneOfInlineOneOf1 *OneOfInlineOneOf1 +} + +func (u OneOfInline) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.OneOfInlineOneOf0 != nil { + count++ + data, err = json.Marshal(u.OneOfInlineOneOf0) + if err != nil { + return nil, err + } + } + if u.OneOfInlineOneOf1 != nil { + count++ + data, err = json.Marshal(u.OneOfInlineOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfInline: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfInline) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 OneOfInlineOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.OneOfInlineOneOf0 = &v0 + successCount++ + } + + var v1 OneOfInlineOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.OneOfInlineOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfInline: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfInline) ApplyDefaults() { + if u.OneOfInlineOneOf0 != nil { + u.OneOfInlineOneOf0.ApplyDefaults() + } + if u.OneOfInlineOneOf1 != nil { + u.OneOfInlineOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/OneOfInline/oneOf/0 +type OneOfInlineOneOf0 struct { + OptionA *string `json:"optionA,omitempty" form:"optionA,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfInlineOneOf0) ApplyDefaults() { +} + +// #/components/schemas/OneOfInline/oneOf/1 +type OneOfInlineOneOf1 struct { + OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfInlineOneOf1) ApplyDefaults() { +} + +// #/components/schemas/OneOfPrimitives +type OneOfPrimitives struct { + String0 *string + Float321 *float32 + Bool2 *bool +} + +func (u OneOfPrimitives) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.String0 != nil { + count++ + data, err = json.Marshal(u.String0) + if err != nil { + return nil, err + } + } + if u.Float321 != nil { + count++ + data, err = json.Marshal(u.Float321) + if err != nil { + return nil, err + } + } + if u.Bool2 != nil { + count++ + data, err = json.Marshal(u.Bool2) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfPrimitives: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfPrimitives) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + successCount++ + } + + var v1 float32 + if err := json.Unmarshal(data, &v1); err == nil { + u.Float321 = &v1 + successCount++ + } + + var v2 bool + if err := json.Unmarshal(data, &v2); err == nil { + u.Bool2 = &v2 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfPrimitives: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfPrimitives) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithOneOfProperty +type ObjectWithOneOfProperty struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + Variant *ObjectWithOneOfPropertyVariant `json:"variant,omitempty" form:"variant,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithOneOfProperty) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithOneOfProperty/properties/variant +type ObjectWithOneOfPropertyVariant struct { + Cat *Cat + Dog *Dog +} + +func (u ObjectWithOneOfPropertyVariant) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.Cat != nil { + count++ + data, err = json.Marshal(u.Cat) + if err != nil { + return nil, err + } + } + if u.Dog != nil { + count++ + data, err = json.Marshal(u.Dog) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("ObjectWithOneOfPropertyVariant: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *ObjectWithOneOfPropertyVariant) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 Cat + if err := json.Unmarshal(data, &v0); err == nil { + u.Cat = &v0 + successCount++ + } + + var v1 Dog + if err := json.Unmarshal(data, &v1); err == nil { + u.Dog = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("ObjectWithOneOfPropertyVariant: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ObjectWithOneOfPropertyVariant) ApplyDefaults() { + if u.Cat != nil { + u.Cat.ApplyDefaults() + } + if u.Dog != nil { + u.Dog.ApplyDefaults() + } +} + +// #/components/schemas/AllOfWithOneOf +type AllOfWithOneOf struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + AllOfWithOneOfAllOf1 *AllOfWithOneOfAllOf1 `json:"-"` +} + +func (s AllOfWithOneOf) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if s.ID != nil { + result["id"] = s.ID + } + if s.CreatedAt != nil { + result["createdAt"] = s.CreatedAt + } + + if s.AllOfWithOneOfAllOf1 != nil { + unionData, err := json.Marshal(s.AllOfWithOneOfAllOf1) + if err != nil { + return nil, err + } + var unionMap map[string]any + if err := json.Unmarshal(unionData, &unionMap); err == nil { + for k, v := range unionMap { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (s *AllOfWithOneOf) UnmarshalJSON(data []byte) error { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["id"]; ok { + var val int + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.ID = &val + } + if v, ok := raw["createdAt"]; ok { + var val time.Time + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.CreatedAt = &val + } + + var AllOfWithOneOfAllOf1Val AllOfWithOneOfAllOf1 + if err := json.Unmarshal(data, &AllOfWithOneOfAllOf1Val); err != nil { + return err + } + s.AllOfWithOneOfAllOf1 = &AllOfWithOneOfAllOf1Val + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithOneOf) ApplyDefaults() { +} + +// #/components/schemas/AllOfWithOneOf/allOf/1 +type AllOfWithOneOfAllOf1 struct { + Cat *Cat + Dog *Dog +} + +func (u AllOfWithOneOfAllOf1) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.Cat != nil { + count++ + data, err = json.Marshal(u.Cat) + if err != nil { + return nil, err + } + } + if u.Dog != nil { + count++ + data, err = json.Marshal(u.Dog) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("AllOfWithOneOfAllOf1: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *AllOfWithOneOfAllOf1) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 Cat + if err := json.Unmarshal(data, &v0); err == nil { + u.Cat = &v0 + successCount++ + } + + var v1 Dog + if err := json.Unmarshal(data, &v1); err == nil { + u.Dog = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("AllOfWithOneOfAllOf1: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AllOfWithOneOfAllOf1) ApplyDefaults() { + if u.Cat != nil { + u.Cat.ApplyDefaults() + } + if u.Dog != nil { + u.Dog.ApplyDefaults() + } +} + +// #/components/schemas/OneOfWithAllOf +type OneOfWithAllOf struct { + OneOfWithAllOfOneOf0 *OneOfWithAllOfOneOf0 + OneOfWithAllOfOneOf1 *OneOfWithAllOfOneOf1 +} + +func (u OneOfWithAllOf) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.OneOfWithAllOfOneOf0 != nil { + count++ + data, err = json.Marshal(u.OneOfWithAllOfOneOf0) + if err != nil { + return nil, err + } + } + if u.OneOfWithAllOfOneOf1 != nil { + count++ + data, err = json.Marshal(u.OneOfWithAllOfOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfWithAllOf: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfWithAllOf) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 OneOfWithAllOfOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.OneOfWithAllOfOneOf0 = &v0 + successCount++ + } + + var v1 OneOfWithAllOfOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.OneOfWithAllOfOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfWithAllOf: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfWithAllOf) ApplyDefaults() { + if u.OneOfWithAllOfOneOf0 != nil { + u.OneOfWithAllOfOneOf0.ApplyDefaults() + } + if u.OneOfWithAllOfOneOf1 != nil { + u.OneOfWithAllOfOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/OneOfWithAllOf/oneOf/0 +type OneOfWithAllOfOneOf0 struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Variant *string `json:"variant,omitempty" form:"variant,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfWithAllOfOneOf0) ApplyDefaults() { +} + +// #/components/schemas/OneOfWithAllOf/oneOf/1 +type OneOfWithAllOfOneOf1 struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Variant *string `json:"variant,omitempty" form:"variant,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfWithAllOfOneOf1) ApplyDefaults() { +} + +// #/components/schemas/TreeNode +type TreeNode struct { + Value *string `json:"value,omitempty" form:"value,omitempty"` + Children []TreeNode `json:"children,omitempty" form:"children,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TreeNode) ApplyDefaults() { +} + +// #/components/schemas/TreeNode/properties/children +type TreeNodeChildren = []TreeNode + +// #/components/schemas/LinkedListNode +type LinkedListNode struct { + Value *int `json:"value,omitempty" form:"value,omitempty"` + Next *LinkedListNode `json:"next,omitempty" form:"next,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *LinkedListNode) ApplyDefaults() { + if s.Next != nil { + s.Next.ApplyDefaults() + } +} + +// #/components/schemas/RecursiveOneOf +type RecursiveOneOf struct { + String0 *string + RecursiveOneOfOneOf1 *RecursiveOneOfOneOf1 +} + +func (u RecursiveOneOf) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.String0 != nil { + count++ + data, err = json.Marshal(u.String0) + if err != nil { + return nil, err + } + } + if u.RecursiveOneOfOneOf1 != nil { + count++ + data, err = json.Marshal(u.RecursiveOneOfOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("RecursiveOneOf: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *RecursiveOneOf) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + successCount++ + } + + var v1 RecursiveOneOfOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.RecursiveOneOfOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("RecursiveOneOf: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *RecursiveOneOf) ApplyDefaults() { + if u.RecursiveOneOfOneOf1 != nil { + u.RecursiveOneOfOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/RecursiveOneOf/oneOf/1 +type RecursiveOneOfOneOf1 struct { + Nested *RecursiveOneOf `json:"nested,omitempty" form:"nested,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *RecursiveOneOfOneOf1) ApplyDefaults() { + if s.Nested != nil { + s.Nested.ApplyDefaults() + } +} + +// #/components/schemas/ReadWriteOnly +type ReadWriteOnly struct { + ID int `json:"id" form:"id"` + Password string `json:"password" form:"password"` + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ReadWriteOnly) ApplyDefaults() { +} + +// #/components/schemas/WithDefaults +type WithDefaults struct { + StringWithDefault *string `json:"stringWithDefault,omitempty" form:"stringWithDefault,omitempty"` + IntWithDefault *int `json:"intWithDefault,omitempty" form:"intWithDefault,omitempty"` + BoolWithDefault *bool `json:"boolWithDefault,omitempty" form:"boolWithDefault,omitempty"` + ArrayWithDefault []string `json:"arrayWithDefault,omitempty" form:"arrayWithDefault,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *WithDefaults) ApplyDefaults() { + if s.StringWithDefault == nil { + v := "default_value" + s.StringWithDefault = &v + } + if s.IntWithDefault == nil { + v := 42 + s.IntWithDefault = &v + } + if s.BoolWithDefault == nil { + v := true + s.BoolWithDefault = &v + } +} + +// #/components/schemas/WithConst +type WithConst struct { + Version *string `json:"version,omitempty" form:"version,omitempty"` + Type *string `json:"type,omitempty" form:"type,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *WithConst) ApplyDefaults() { +} + +// #/components/schemas/WithConstraints +type WithConstraints struct { + BoundedInt *int `json:"boundedInt,omitempty" form:"boundedInt,omitempty"` + ExclusiveBoundedInt *int `json:"exclusiveBoundedInt,omitempty" form:"exclusiveBoundedInt,omitempty"` + MultipleOf *int `json:"multipleOf,omitempty" form:"multipleOf,omitempty"` + BoundedString *string `json:"boundedString,omitempty" form:"boundedString,omitempty"` + PatternString *string `json:"patternString,omitempty" form:"patternString,omitempty"` + BoundedArray []string `json:"boundedArray,omitempty" form:"boundedArray,omitempty"` + UniqueArray []string `json:"uniqueArray,omitempty" form:"uniqueArray,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *WithConstraints) ApplyDefaults() { +} + +// #/components/schemas/TypeArray31 +type TypeArray31 struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TypeArray31) ApplyDefaults() { +} + +// #/components/schemas/ExplicitAny +type ExplicitAny = Nullable[string] + +// #/components/schemas/ComplexNested +type ComplexNested struct { + Metadata map[string]any `json:"metadata,omitempty" form:"metadata,omitempty"` + Items []ComplexNestedItemItem `json:"items,omitempty" form:"items,omitempty"` + Config *ComplexNestedConfig `json:"config,omitempty" form:"config,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexNested) ApplyDefaults() { +} + +// #/components/schemas/ComplexNested/properties/metadata +type ComplexNestedMetadata = map[string]any + +// #/components/schemas/ComplexNested/properties/metadata/additionalProperties +type ComplexNestedMetadataValue struct { + String0 *string + Int1 *int + LBracketString2 *[]string +} + +func (u ComplexNestedMetadataValue) MarshalJSON() ([]byte, error) { + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.Int1 != nil { + return json.Marshal(u.Int1) + } + if u.LBracketString2 != nil { + return json.Marshal(u.LBracketString2) + } + return []byte("null"), nil +} + +func (u *ComplexNestedMetadataValue) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 int + if err := json.Unmarshal(data, &v1); err == nil { + u.Int1 = &v1 + } + + var v2 []string + if err := json.Unmarshal(data, &v2); err == nil { + u.LBracketString2 = &v2 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ComplexNestedMetadataValue) ApplyDefaults() { +} + +// #/components/schemas/ComplexNested/properties/items +type ComplexNestedItem = []ComplexNestedItemItem + +// #/components/schemas/ComplexNested/properties/items/items +type ComplexNestedItemItem struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` + Tags []string `json:"tags,omitempty" form:"tags,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexNestedItemItem) ApplyDefaults() { +} + +// #/components/schemas/ComplexNested/properties/config +type ComplexNestedConfig struct { + ComplexNestedConfigOneOf0 *ComplexNestedConfigOneOf0 + ComplexNestedConfigOneOf1 *ComplexNestedConfigOneOf1 +} + +func (u ComplexNestedConfig) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.ComplexNestedConfigOneOf0 != nil { + count++ + data, err = json.Marshal(u.ComplexNestedConfigOneOf0) + if err != nil { + return nil, err + } + } + if u.ComplexNestedConfigOneOf1 != nil { + count++ + data, err = json.Marshal(u.ComplexNestedConfigOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("ComplexNestedConfig: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *ComplexNestedConfig) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 ComplexNestedConfigOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.ComplexNestedConfigOneOf0 = &v0 + successCount++ + } + + var v1 ComplexNestedConfigOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.ComplexNestedConfigOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("ComplexNestedConfig: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ComplexNestedConfig) ApplyDefaults() { + if u.ComplexNestedConfigOneOf0 != nil { + u.ComplexNestedConfigOneOf0.ApplyDefaults() + } + if u.ComplexNestedConfigOneOf1 != nil { + u.ComplexNestedConfigOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/ComplexNested/properties/config/oneOf/0 +type ComplexNestedConfigOneOf0 struct { + Mode *string `json:"mode,omitempty" form:"mode,omitempty"` + Value *string `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexNestedConfigOneOf0) ApplyDefaults() { +} + +// #/components/schemas/ComplexNested/properties/config/oneOf/1 +type ComplexNestedConfigOneOf1 struct { + Mode *string `json:"mode,omitempty" form:"mode,omitempty"` + Options map[string]string `json:"options,omitempty" form:"options,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexNestedConfigOneOf1) ApplyDefaults() { +} + +// #/components/schemas/ComplexNested/properties/config/oneOf/1/properties/options +type ComplexNestedConfigOneOf1Options = map[string]string + +// #/components/schemas/StringMap +type StringMap = map[string]string + +// #/components/schemas/ObjectMap +type ObjectMap = map[string]any + +// #/components/schemas/NestedMap +type NestedMap = map[string]map[string]string + +// #/components/schemas/NestedMap/additionalProperties +type NestedMapValue = map[string]string + +// #/paths//inline-response/get/responses/200/content/application/json/schema +type GetInlineResponseJSONResponse struct { + ID int `json:"id" form:"id"` + Name string `json:"name" form:"name"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *GetInlineResponseJSONResponse) ApplyDefaults() { +} + +const DateFormat = "2006-01-02" + +type Date struct { + time.Time +} + +func (d Date) MarshalJSON() ([]byte, error) { + return json.Marshal(d.Format(DateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var dateStr string + err := json.Unmarshal(data, &dateStr) + if err != nil { + return err + } + parsed, err := time.Parse(DateFormat, dateStr) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +func (d Date) String() string { + return d.Format(DateFormat) +} + +func (d *Date) UnmarshalText(data []byte) error { + parsed, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +const ( + emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" +) + +var ( + emailRegex = regexp.MustCompile(emailRegexString) +) + +// ErrValidationEmail is the sentinel error returned when an email fails validation +var ErrValidationEmail = errors.New("email: failed to pass regex validation") + +// Email represents an email address. +// It is a string type that must pass regex validation before being marshalled +// to JSON or unmarshalled from JSON. +type Email string + +func (e Email) MarshalJSON() ([]byte, error) { + if !emailRegex.MatchString(string(e)) { + return nil, ErrValidationEmail + } + + return json.Marshal(string(e)) +} + +func (e *Email) UnmarshalJSON(data []byte) error { + if e == nil { + return nil + } + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *e = Email(s) + if !emailRegex.MatchString(s) { + return ErrValidationEmail + } + + return nil +} + +type File struct { + multipart *multipart.FileHeader + data []byte + filename string +} + +func (file *File) InitFromMultipart(header *multipart.FileHeader) { + file.multipart = header + file.data = nil + file.filename = "" +} + +func (file *File) InitFromBytes(data []byte, filename string) { + file.data = data + file.filename = filename + file.multipart = nil +} + +func (file File) MarshalJSON() ([]byte, error) { + b, err := file.Bytes() + if err != nil { + return nil, err + } + return json.Marshal(b) +} + +func (file *File) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &file.data) +} + +func (file File) Bytes() ([]byte, error) { + if file.multipart != nil { + f, err := file.multipart.Open() + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + return io.ReadAll(f) + } + return file.data, nil +} + +func (file File) Reader() (io.ReadCloser, error) { + if file.multipart != nil { + return file.multipart.Open() + } + return io.NopCloser(bytes.NewReader(file.data)), nil +} + +func (file File) Filename() string { + if file.multipart != nil { + return file.multipart.Filename + } + return file.filename +} + +func (file File) FileSize() int64 { + if file.multipart != nil { + return file.multipart.Size + } + return int64(len(file.data)) +} + +// Nullable is a generic type that can distinguish between: +// - Field not provided (unspecified) +// - Field explicitly set to null +// - Field has a value +// +// This is implemented as a map[bool]T where: +// - Empty map: unspecified +// - map[false]T: explicitly null +// - map[true]T: has a value +type Nullable[T any] map[bool]T + +// NewNullableWithValue creates a Nullable with the given value. +func NewNullableWithValue[T any](value T) Nullable[T] { + return Nullable[T]{true: value} +} + +// NewNullNullable creates a Nullable that is explicitly null. +func NewNullNullable[T any]() Nullable[T] { + return Nullable[T]{false: *new(T)} +} + +// Get returns the value if set, or an error if null or unspecified. +func (n Nullable[T]) Get() (T, error) { + if v, ok := n[true]; ok { + return v, nil + } + var zero T + if n.IsNull() { + return zero, ErrNullableIsNull + } + return zero, ErrNullableNotSpecified +} + +// MustGet returns the value or panics if null or unspecified. +func (n Nullable[T]) MustGet() T { + v, err := n.Get() + if err != nil { + panic(err) + } + return v +} + +// Set assigns a value. +func (n *Nullable[T]) Set(value T) { + *n = Nullable[T]{true: value} +} + +// SetNull marks the field as explicitly null. +func (n *Nullable[T]) SetNull() { + *n = Nullable[T]{false: *new(T)} +} + +// SetUnspecified clears the field (as if it was never set). +func (n *Nullable[T]) SetUnspecified() { + *n = nil +} + +// IsNull returns true if the field is explicitly null. +func (n Nullable[T]) IsNull() bool { + if n == nil { + return false + } + _, ok := n[false] + return ok +} + +// IsSpecified returns true if the field was provided (either null or a value). +func (n Nullable[T]) IsSpecified() bool { + return len(n) > 0 +} + +// MarshalJSON implements json.Marshaler. +func (n Nullable[T]) MarshalJSON() ([]byte, error) { + if n.IsNull() { + return []byte("null"), nil + } + if v, ok := n[true]; ok { + return json.Marshal(v) + } + // Unspecified - this shouldn't be called if omitempty is used correctly + return []byte("null"), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *Nullable[T]) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + n.SetNull() + return nil + } + var v T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + n.Set(v) + return nil +} + +// ErrNullableIsNull is returned when trying to get a value from a null Nullable. +var ErrNullableIsNull = errors.New("nullable value is null") + +// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. +var ErrNullableNotSpecified = errors.New("nullable value is not specified") + +type UUID = uuid.UUID + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/+wcXW8iOfKdX2Gx+3Zi8jGz84B0D4QwEnsEEJCdi1Z7J4cuEu90u3vcJgm32v9+st10", + "tz/6y2RGs6PNEynb9eVyVblcECdAcUKGqP/2zcWb836P0F087CHECQ9hiMZxlDB4BJqSJ0AbSDlabx8h", + "wj2EnoClJKZD1L94cy7WIhRAumUk4RIsZqcIhyFK5RKUYM6B0RTtYoZinJDBNg7gAWivl2D+mAq6ZymJ", + "khDER4QegKsPCMUJMCzwToOhgK/ltGyQQZrENIX0OBuh/uX5eb/412BNrc7XlaZtY8qB8vJKhHCShGQr", + "yZ/9nsZUH0WZfCYUoR8Z7Iao/8PZNo6SmALl6Zmam54pFhb3v8OW93tCckJDQmFwZKpRBVM5f6XL0FkV", + "CguKJSOI0C+uFH5IYJjRswYZfN4TBoG9DKEBIoETTHEE1kDChL44KWui+CNOCkfmCOXwAMwxQ5CqW5ly", + "RuiD3M4EMxwBB5ae/SHMeyn+/1MtLsaOyJQUQ5TPzIkQqqA9S0eIs30huK1vjaUCvItZhPkQ7feZPmts", + "7CPJ2JHMZpNs7gv+P++BHdYmSSGDHOnV24eTYw31lHJvvOa2aohHjOGDN2psrEaIcIgs06uV7xFwAEzf", + "fMWHGumuu87OYPGvb8MVChOHlA/u4+CQnZg4dRupGFip6VdxcOgVZySDDJsOjkPOeindMtZJOArDzSGB", + "dJVx0P+rb1C0D7kI3yUGanfoRswfq+l1W/QV9kIXxk3nZfD8/DwQjnKwZyFQkacEX4qw1GWCGT+TBAPM", + "cRtSNXG0LvbtSOiMYBXBwgwa94RidrAmRMCxzfj35Zg0meCFnyUhJh3TnmN+UBATMzN6atEP6J/t/7IV", + "y9X0ZrqZ/jJBm7vlZI0GaBSG2Z6lHljlEtNpHWVyGJ6dtg1EtP1AIAx00NtLB/D9OxO4C2NsLQ/i/X0I", + "JpTuo3tgJlQp2oTex3FoYcUcXLANiSy4SJlMGESYWEj3jJigxzjlItBb8idP7xyw9xbvB5tPdRpNaILT", + "9DlmGqcul3DcITtnNDOlYuOa5xa+Qq4q48j2uSOO9+9yeGEWNg5lBw4UclEOLxlRBxxqVT5QsrlGJCVL", + "bEzOc/u0Z4ohwLSQ42i2HTJ+sUZDkNt4RyQDTkpXrvxU+Fw+xF9xhDpgkIsKHrID14UFRnKodjg74Diu", + "K6z8eJo7IBFrygjeeyB4X9jQobthiDUFgsKpdEGhJwaaD+qA5rhOD0ELmQbgsCYE/e3g/nZw36OD884J", + "57ez2ehqlqWEvkngfB+G+D4EzySQZsvXVskjGyjXcwrooulk63gtpfb0AqHjVjNAfYGjb2Gc6hcLFzpX", + "ebASnxKlCaXjGmdhrL7XuaqSZj2y2EpPZ/rtqtz7iIxWq9Gd99GQFUMZnjpqUulGLrfdgVlJdNQRnX6D", + "UH4qRlPJShB/rN2v1uoJZHEi3crKSHVdxPUeUPcW4H4HcG4MhZRDcKo0pxSYj+fMzYNxpmxCDkfU1igl", + "so+EP45jmnKGSVbwqJctInQqCaCLMhS/HKHnHVjxdg6Lq58n4423dygbeNfKSe2lvUV2aVqnIxZIo2zk", + "zsVAvOfAbOzWcas6bIRSff0JxcwnHO6bq5n+8eH6erqZLuajGVquFsvJajP1z6RGQUBU4F2yOElH9FCj", + "eKxNzsRXzxYuZPOYQmdsOxzmr7wuJX+i8TOtNyODDREMg6589Ny27MLfaK/1BDo9cVjE5VOo+ND1Etp4", + "YNuo5VRTnsxvb/x9mSQ+oftIl13z9lAaFl5Mns0LE3BpAt4qElOlEZuGriqTSBl/GXWGVe2n2DkbcYs0", + "DfN92uLCpjOV1WCBBnYCjLecPIEBFNYYAofiupgwEjPCD23qCC7iF8b/l8b/uc5FtiU0M6WZ5R06V1gE", + "ivUpmoqpCdjtTnDZs9niAxqgKX0ERjimWzgbi+OeyiPmewKucAr24Xw1D4DQlgEWaSL3KlTIwckLBxqY", + "UR2H4WJXPjJ1XlAXs19aVRGg3f06VkuO98W1PFB+EGy87F4DJCUb8NKGrtAW2qgSE144w808jwRz8qU8", + "CWEFu/SV97D7fayzpBGwB7t7Sy/wFbIqB7Sg4aFS0o70d4SlvGXXTUfUKWxjWiGalrR4ua35nXRbt5TE", + "FMmigneeSQ+L3ZKRiIhYU9iQANuardCKnoWJpco0qtH5GFcXMy44uSEvhYm1Fesr2L6KhW1sX/B8rMb5", + "7U+58lUkOdnWe0Vy6yplMFTDlMtwXGO6EsSlf7EblanY5QDjdm/xNPDq3/CwPK8KwnwiD/U1EYErIlRE", + "eHXEvU/3gsJity71SCMUC9BXP4qSEWF0Jeli5sXTGLdm5Tp+OE4NXHRz2z7MVTstcOFM61i+wUlSKmh/", + "a5wX5S+NTZkziiSwBWMIBfFDLV9y6hh3LVSZPA5QBPFzjZPJFjTmuAJN46TnR5J+AjYD+sAfK18pVTYY", + "P5ws2j1mn15BNIGmcRLHJGwjl7ToqRZ3LPvtGMVimWCPvkwOpZBftUiipGR2FlMhXQVfxkO1Mw4V0TMj", + "6XcPbnHFe8KMYP2pyxCno8Pp5HRqHE+D2/QJfePFzdV0PrkWH5aLtayintCHqNz2oqytV7oT/SV2IA9c", + "o7LQ1lkwVOKvltqz3VyTt8y8ZY/xNqapiGi4/x0KdX9CIrmajG9X67y91/cgbRjAPA7g1JuBU+LtIwkD", + "BvTVX4qPXGf6mxH6CYIZSfnriWK9n8GLttV17On8ZEyuYLtnKXkCzWV1C16tg6p6YO7yTQSdvZMMc3R9", + "9nE13UzQYj678zXMFeDgIyNcKwV1fSwtdz6fGKkFJRxIZvSvCh3xtyjSPufy6Cia32Z9NuJ68mF0O9us", + "0WguYu58vfHdC3k/gh3eh9yvr6WEoIWagmwm6mef/ivPaLklhNditPcuR/nuUus7rEVjdh+W0Gjbl3c0", + "VGLybeApUfz1t2IvZOdEVzeXfTO7Wf3H6JR/g9vdGNKwekdeIOifki3O15vVaDr3b7eoaDJpqbD7eE8D", + "CFyNaA4Diwgl0T4aonO9PUUBL84LMLxsw71wtFedCOTLblyUilEXySh7P9CTpkpRitnoJ1MdFZ1+th1E", + "hGa3VbNj5wi+/OmnkhOVPwPQGns2f4j6//kVD/732z9+7JuctuyuetXGorw5mJLPe2jJgZqckdMcy5fs", + "ZFpO5qPlFL19c4HWy8l4+mE69s4hD4mS9e2FdsZ6lb2sRvuYs7W0MSYuGeyI2iaDsKbipJjW+amjqkrg", + "3JxXasq4WW7u0Bkaze9kZu+7KZMo4Qf1uxxD9Mef+SvDL+V0V/s+5Wi7hYSnCNMD+nm9mKvM+PiOnIRk", + "S7jZodSr7O4d2JUWW6tmhDVbDasN55QqxHI2+TeaT9abyTVab1a3483tyv8GNZatGi9zLeNuGWNcX5Gt", + "yPTrG4IqHmdqn2fqH2iKUbv7s7LVtLoT2ZzdOi9y3PVPue033PebfiOE44e07rc+3Lqq1Vf17TmmO/LQ", + "WBr0rF5EpZuyR+lC/SRP37P78luQAAdPmG6L310wK9I1xl1hOm0O6esGi5vR8sQGvhucnNicWZZBFc5P", + "wdmxH1N53dOFMHa0aR81yf8fAAD//ynhbdUwSwAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/default_values/default_values.yaml b/experimental/internal/codegen/test/default_values/default_values.yaml new file mode 100644 index 0000000000..8f773e63ee --- /dev/null +++ b/experimental/internal/codegen/test/default_values/default_values.yaml @@ -0,0 +1,158 @@ +openapi: "3.1.0" +info: + title: Default Values Test + version: "1.0" +paths: {} +components: + schemas: + # Basic primitives with defaults + SimpleDefaults: + type: object + properties: + stringField: + type: string + default: "hello" + intField: + type: integer + default: 42 + boolField: + type: boolean + default: true + floatField: + type: number + default: 3.14 + int64Field: + type: integer + format: int64 + default: 9223372036854775807 + + # Nested objects - should recurse ApplyDefaults + NestedDefaults: + type: object + properties: + name: + type: string + default: "parent" + child: + $ref: '#/components/schemas/SimpleDefaults' + inlineChild: + type: object + properties: + label: + type: string + default: "inline-default" + value: + type: integer + default: 100 + + # Object with additionalProperties and defaults + MapWithDefaults: + type: object + properties: + prefix: + type: string + default: "map-" + additionalProperties: + type: string + + # Array field with defaults + ArrayDefaults: + type: object + properties: + items: + type: array + items: + type: string + default: [] + count: + type: integer + default: 0 + + # anyOf with defaults in members + AnyOfWithDefaults: + type: object + properties: + value: + anyOf: + - type: object + properties: + stringVal: + type: string + default: "default-string" + - type: object + properties: + intVal: + type: integer + default: 999 + + # oneOf with defaults in members + OneOfWithDefaults: + type: object + properties: + variant: + oneOf: + - type: object + properties: + optionA: + type: string + default: "option-a-default" + - type: object + properties: + optionB: + type: integer + default: 123 + + # allOf with defaults + AllOfWithDefaults: + allOf: + - type: object + properties: + base: + type: string + default: "base-value" + - type: object + properties: + extended: + type: integer + default: 50 + + # Deep nesting - multiple levels + DeepNesting: + type: object + properties: + level1: + type: object + properties: + name: + type: string + default: "level1-name" + level2: + type: object + properties: + count: + type: integer + default: 2 + level3: + type: object + properties: + enabled: + type: boolean + default: false + + # Required vs optional with defaults + RequiredAndOptional: + type: object + required: + - requiredWithDefault + - requiredNoDefault + properties: + requiredWithDefault: + type: string + default: "required-default" + requiredNoDefault: + type: string + optionalWithDefault: + type: string + default: "optional-default" + optionalNoDefault: + type: string diff --git a/experimental/internal/codegen/test/default_values/output/default_values.gen.go b/experimental/internal/codegen/test/default_values/output/default_values.gen.go new file mode 100644 index 0000000000..a8b988994d --- /dev/null +++ b/experimental/internal/codegen/test/default_values/output/default_values.gen.go @@ -0,0 +1,514 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "encoding/json" + "fmt" +) + +// #/components/schemas/SimpleDefaults +type SimpleDefaultsSchemaComponent struct { + StringField *string `json:"stringField,omitempty" form:"stringField,omitempty"` + IntField *int `json:"intField,omitempty" form:"intField,omitempty"` + BoolField *bool `json:"boolField,omitempty" form:"boolField,omitempty"` + FloatField *float32 `json:"floatField,omitempty" form:"floatField,omitempty"` + Int64Field *int64 `json:"int64Field,omitempty" form:"int64Field,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *SimpleDefaultsSchemaComponent) ApplyDefaults() { + if s.StringField == nil { + v := "hello" + s.StringField = &v + } + if s.IntField == nil { + v := 42 + s.IntField = &v + } + if s.BoolField == nil { + v := true + s.BoolField = &v + } + if s.FloatField == nil { + v := float32(3.14) + s.FloatField = &v + } + if s.Int64Field == nil { + v := int64(9223372036854775807) + s.Int64Field = &v + } +} + +type SimpleDefaults = SimpleDefaultsSchemaComponent + +// #/components/schemas/NestedDefaults +type NestedDefaultsSchemaComponent struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` + Child *SimpleDefaults `json:"child,omitempty" form:"child,omitempty"` + InlineChild *NestedDefaultsInlineChild `json:"inlineChild,omitempty" form:"inlineChild,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NestedDefaultsSchemaComponent) ApplyDefaults() { + if s.Name == nil { + v := "parent" + s.Name = &v + } + if s.Child != nil { + s.Child.ApplyDefaults() + } + if s.InlineChild != nil { + s.InlineChild.ApplyDefaults() + } +} + +type NestedDefaults = NestedDefaultsSchemaComponent + +// #/components/schemas/NestedDefaults/properties/inlineChild +type NestedDefaultsInlineChildPropertySchemaComponent struct { + Label *string `json:"label,omitempty" form:"label,omitempty"` + Value *int `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *NestedDefaultsInlineChildPropertySchemaComponent) ApplyDefaults() { + if s.Label == nil { + v := "inline-default" + s.Label = &v + } + if s.Value == nil { + v := 100 + s.Value = &v + } +} + +type NestedDefaultsInlineChild = NestedDefaultsInlineChildPropertySchemaComponent + +// #/components/schemas/MapWithDefaults +type MapWithDefaultsSchemaComponent struct { + Prefix *string `json:"prefix,omitempty" form:"prefix,omitempty"` + AdditionalProperties map[string]string `json:"-"` +} + +func (s MapWithDefaultsSchemaComponent) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if s.Prefix != nil { + result["prefix"] = s.Prefix + } + + // Add additional properties + for k, v := range s.AdditionalProperties { + result[k] = v + } + + return json.Marshal(result) +} + +func (s *MapWithDefaultsSchemaComponent) UnmarshalJSON(data []byte) error { + // Known fields + knownFields := map[string]bool{ + "prefix": true, + } + + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["prefix"]; ok { + var val string + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.Prefix = &val + } + + // Collect additional properties + s.AdditionalProperties = make(map[string]string) + for k, v := range raw { + if !knownFields[k] { + var val string + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.AdditionalProperties[k] = val + } + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *MapWithDefaultsSchemaComponent) ApplyDefaults() { + if s.Prefix == nil { + v := "map-" + s.Prefix = &v + } +} + +type MapWithDefaults = MapWithDefaultsSchemaComponent + +// #/components/schemas/ArrayDefaults +type ArrayDefaultsSchemaComponent struct { + Items []string `json:"items,omitempty" form:"items,omitempty"` + Count *int `json:"count,omitempty" form:"count,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ArrayDefaultsSchemaComponent) ApplyDefaults() { + if s.Count == nil { + v := 0 + s.Count = &v + } +} + +type ArrayDefaults = ArrayDefaultsSchemaComponent + +// #/components/schemas/AnyOfWithDefaults +type AnyOfWithDefaultsSchemaComponent struct { + Value *AnyOfWithDefaultsValue `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AnyOfWithDefaultsSchemaComponent) ApplyDefaults() { +} + +type AnyOfWithDefaults = AnyOfWithDefaultsSchemaComponent + +// #/components/schemas/AnyOfWithDefaults/properties/value +type AnyOfWithDefaultsValuePropertySchemaComponent struct { + AnyOfWithDefaultsValueAnyOf0 *AnyOfWithDefaultsValueAnyOf0 + AnyOfWithDefaultsValueAnyOf1 *AnyOfWithDefaultsValueAnyOf1 +} + +func (u AnyOfWithDefaultsValuePropertySchemaComponent) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.AnyOfWithDefaultsValueAnyOf0 != nil { + data, err := json.Marshal(u.AnyOfWithDefaultsValueAnyOf0) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.AnyOfWithDefaultsValueAnyOf1 != nil { + data, err := json.Marshal(u.AnyOfWithDefaultsValueAnyOf1) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *AnyOfWithDefaultsValuePropertySchemaComponent) UnmarshalJSON(data []byte) error { + var v0 AnyOfWithDefaultsValueAnyOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.AnyOfWithDefaultsValueAnyOf0 = &v0 + } + + var v1 AnyOfWithDefaultsValueAnyOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.AnyOfWithDefaultsValueAnyOf1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AnyOfWithDefaultsValuePropertySchemaComponent) ApplyDefaults() { + if u.AnyOfWithDefaultsValueAnyOf0 != nil { + u.AnyOfWithDefaultsValueAnyOf0.ApplyDefaults() + } + if u.AnyOfWithDefaultsValueAnyOf1 != nil { + u.AnyOfWithDefaultsValueAnyOf1.ApplyDefaults() + } +} + +type AnyOfWithDefaultsValue = AnyOfWithDefaultsValuePropertySchemaComponent + +// #/components/schemas/AnyOfWithDefaults/properties/value/anyOf/0 +type AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent struct { + StringVal *string `json:"stringVal,omitempty" form:"stringVal,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent) ApplyDefaults() { + if s.StringVal == nil { + v := "default-string" + s.StringVal = &v + } +} + +type AnyOfWithDefaultsValueAnyOf0 = AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent + +// #/components/schemas/AnyOfWithDefaults/properties/value/anyOf/1 +type AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent struct { + IntVal *int `json:"intVal,omitempty" form:"intVal,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent) ApplyDefaults() { + if s.IntVal == nil { + v := 999 + s.IntVal = &v + } +} + +type AnyOfWithDefaultsValueAnyOf1 = AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent + +// #/components/schemas/OneOfWithDefaults +type OneOfWithDefaultsSchemaComponent struct { + Variant *OneOfWithDefaultsVariant `json:"variant,omitempty" form:"variant,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfWithDefaultsSchemaComponent) ApplyDefaults() { +} + +type OneOfWithDefaults = OneOfWithDefaultsSchemaComponent + +// #/components/schemas/OneOfWithDefaults/properties/variant +type OneOfWithDefaultsVariantPropertySchemaComponent struct { + OneOfWithDefaultsVariantOneOf0 *OneOfWithDefaultsVariantOneOf0 + OneOfWithDefaultsVariantOneOf1 *OneOfWithDefaultsVariantOneOf1 +} + +func (u OneOfWithDefaultsVariantPropertySchemaComponent) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.OneOfWithDefaultsVariantOneOf0 != nil { + count++ + data, err = json.Marshal(u.OneOfWithDefaultsVariantOneOf0) + if err != nil { + return nil, err + } + } + if u.OneOfWithDefaultsVariantOneOf1 != nil { + count++ + data, err = json.Marshal(u.OneOfWithDefaultsVariantOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("OneOfWithDefaultsVariantPropertySchemaComponent: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *OneOfWithDefaultsVariantPropertySchemaComponent) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 OneOfWithDefaultsVariantOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.OneOfWithDefaultsVariantOneOf0 = &v0 + successCount++ + } + + var v1 OneOfWithDefaultsVariantOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.OneOfWithDefaultsVariantOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("OneOfWithDefaultsVariantPropertySchemaComponent: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *OneOfWithDefaultsVariantPropertySchemaComponent) ApplyDefaults() { + if u.OneOfWithDefaultsVariantOneOf0 != nil { + u.OneOfWithDefaultsVariantOneOf0.ApplyDefaults() + } + if u.OneOfWithDefaultsVariantOneOf1 != nil { + u.OneOfWithDefaultsVariantOneOf1.ApplyDefaults() + } +} + +type OneOfWithDefaultsVariant = OneOfWithDefaultsVariantPropertySchemaComponent + +// #/components/schemas/OneOfWithDefaults/properties/variant/oneOf/0 +type OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent struct { + OptionA *string `json:"optionA,omitempty" form:"optionA,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent) ApplyDefaults() { + if s.OptionA == nil { + v := "option-a-default" + s.OptionA = &v + } +} + +type OneOfWithDefaultsVariantOneOf0 = OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent + +// #/components/schemas/OneOfWithDefaults/properties/variant/oneOf/1 +type OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent struct { + OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent) ApplyDefaults() { + if s.OptionB == nil { + v := 123 + s.OptionB = &v + } +} + +type OneOfWithDefaultsVariantOneOf1 = OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent + +// #/components/schemas/AllOfWithDefaults +type AllOfWithDefaultsSchemaComponent struct { + Base *string `json:"base,omitempty" form:"base,omitempty"` + Extended *int `json:"extended,omitempty" form:"extended,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithDefaultsSchemaComponent) ApplyDefaults() { + if s.Base == nil { + v := "base-value" + s.Base = &v + } + if s.Extended == nil { + v := 50 + s.Extended = &v + } +} + +type AllOfWithDefaults = AllOfWithDefaultsSchemaComponent + +// #/components/schemas/AllOfWithDefaults/allOf/0 +type AllOfWithDefaultsN0AllOfSchemaComponent struct { + Base *string `json:"base,omitempty" form:"base,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithDefaultsN0AllOfSchemaComponent) ApplyDefaults() { + if s.Base == nil { + v := "base-value" + s.Base = &v + } +} + +type AllOfWithDefaultsAllOf0 = AllOfWithDefaultsN0AllOfSchemaComponent + +// #/components/schemas/AllOfWithDefaults/allOf/1 +type AllOfWithDefaultsN1AllOfSchemaComponent struct { + Extended *int `json:"extended,omitempty" form:"extended,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithDefaultsN1AllOfSchemaComponent) ApplyDefaults() { + if s.Extended == nil { + v := 50 + s.Extended = &v + } +} + +type AllOfWithDefaultsAllOf1 = AllOfWithDefaultsN1AllOfSchemaComponent + +// #/components/schemas/DeepNesting +type DeepNestingSchemaComponent struct { + Level1 *DeepNestingLevel1 `json:"level1,omitempty" form:"level1,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DeepNestingSchemaComponent) ApplyDefaults() { + if s.Level1 != nil { + s.Level1.ApplyDefaults() + } +} + +type DeepNesting = DeepNestingSchemaComponent + +// #/components/schemas/DeepNesting/properties/level1 +type DeepNestingLevel1PropertySchemaComponent struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` + Level2 *DeepNestingLevel1Level2 `json:"level2,omitempty" form:"level2,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DeepNestingLevel1PropertySchemaComponent) ApplyDefaults() { + if s.Name == nil { + v := "level1-name" + s.Name = &v + } + if s.Level2 != nil { + s.Level2.ApplyDefaults() + } +} + +type DeepNestingLevel1 = DeepNestingLevel1PropertySchemaComponent + +// #/components/schemas/DeepNesting/properties/level1/properties/level2 +type DeepNestingLevel1Level2PropertyPropertySchemaComponent struct { + Count *int `json:"count,omitempty" form:"count,omitempty"` + Level3 *DeepNestingLevel1Level2Level3 `json:"level3,omitempty" form:"level3,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DeepNestingLevel1Level2PropertyPropertySchemaComponent) ApplyDefaults() { + if s.Count == nil { + v := 2 + s.Count = &v + } + if s.Level3 != nil { + s.Level3.ApplyDefaults() + } +} + +type DeepNestingLevel1Level2 = DeepNestingLevel1Level2PropertyPropertySchemaComponent + +// #/components/schemas/DeepNesting/properties/level1/properties/level2/properties/level3 +type DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent struct { + Enabled *bool `json:"enabled,omitempty" form:"enabled,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent) ApplyDefaults() { + if s.Enabled == nil { + v := false + s.Enabled = &v + } +} + +type DeepNestingLevel1Level2Level3 = DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent + +// #/components/schemas/RequiredAndOptional +type RequiredAndOptionalSchemaComponent struct { + RequiredWithDefault string `json:"requiredWithDefault" form:"requiredWithDefault"` + RequiredNoDefault string `json:"requiredNoDefault" form:"requiredNoDefault"` + OptionalWithDefault *string `json:"optionalWithDefault,omitempty" form:"optionalWithDefault,omitempty"` + OptionalNoDefault *string `json:"optionalNoDefault,omitempty" form:"optionalNoDefault,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *RequiredAndOptionalSchemaComponent) ApplyDefaults() { + if s.OptionalWithDefault == nil { + v := "optional-default" + s.OptionalWithDefault = &v + } +} + +type RequiredAndOptional = RequiredAndOptionalSchemaComponent diff --git a/experimental/internal/codegen/test/default_values/output/default_values_test.go b/experimental/internal/codegen/test/default_values/output/default_values_test.go new file mode 100644 index 0000000000..ccee0f18e3 --- /dev/null +++ b/experimental/internal/codegen/test/default_values/output/default_values_test.go @@ -0,0 +1,324 @@ +package output + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ptr[T any](v T) *T { + return &v +} + +// TestSimpleDefaults tests ApplyDefaults on basic primitive types +func TestSimpleDefaults(t *testing.T) { + t.Run("applies all defaults to empty struct", func(t *testing.T) { + s := SimpleDefaults{} + s.ApplyDefaults() + + require.NotNil(t, s.StringField) + assert.Equal(t, "hello", *s.StringField) + + require.NotNil(t, s.IntField) + assert.Equal(t, 42, *s.IntField) + + require.NotNil(t, s.BoolField) + assert.Equal(t, true, *s.BoolField) + + require.NotNil(t, s.FloatField) + assert.Equal(t, float32(3.14), *s.FloatField) + + require.NotNil(t, s.Int64Field) + assert.Equal(t, int64(9223372036854775807), *s.Int64Field) + }) + + t.Run("does not overwrite existing values", func(t *testing.T) { + s := SimpleDefaults{ + StringField: ptr("custom"), + IntField: ptr(100), + BoolField: ptr(false), + FloatField: ptr(float32(1.5)), + Int64Field: ptr(int64(123)), + } + s.ApplyDefaults() + + assert.Equal(t, "custom", *s.StringField) + assert.Equal(t, 100, *s.IntField) + assert.Equal(t, false, *s.BoolField) + assert.Equal(t, float32(1.5), *s.FloatField) + assert.Equal(t, int64(123), *s.Int64Field) + }) + + t.Run("applies defaults after unmarshaling empty object", func(t *testing.T) { + input := `{}` + var s SimpleDefaults + err := json.Unmarshal([]byte(input), &s) + require.NoError(t, err) + + s.ApplyDefaults() + + assert.Equal(t, "hello", *s.StringField) + assert.Equal(t, 42, *s.IntField) + }) + + t.Run("applies defaults after unmarshaling partial object", func(t *testing.T) { + input := `{"stringField": "from-json"}` + var s SimpleDefaults + err := json.Unmarshal([]byte(input), &s) + require.NoError(t, err) + + s.ApplyDefaults() + + assert.Equal(t, "from-json", *s.StringField) // from JSON + assert.Equal(t, 42, *s.IntField) // from default + }) +} + +// TestNestedDefaults tests ApplyDefaults recursion into nested structs +func TestNestedDefaults(t *testing.T) { + t.Run("applies defaults to parent and recurses to children", func(t *testing.T) { + n := NestedDefaults{ + Child: &SimpleDefaults{}, + InlineChild: &NestedDefaultsInlineChild{}, + } + n.ApplyDefaults() + + // Parent defaults + require.NotNil(t, n.Name) + assert.Equal(t, "parent", *n.Name) + + // Child defaults (recursion) + require.NotNil(t, n.Child.StringField) + assert.Equal(t, "hello", *n.Child.StringField) + require.NotNil(t, n.Child.IntField) + assert.Equal(t, 42, *n.Child.IntField) + + // Inline child defaults (recursion) + require.NotNil(t, n.InlineChild.Label) + assert.Equal(t, "inline-default", *n.InlineChild.Label) + require.NotNil(t, n.InlineChild.Value) + assert.Equal(t, 100, *n.InlineChild.Value) + }) + + t.Run("does not recurse into nil children", func(t *testing.T) { + n := NestedDefaults{} + n.ApplyDefaults() + + // Parent defaults applied + require.NotNil(t, n.Name) + assert.Equal(t, "parent", *n.Name) + + // Children are still nil (not created) + assert.Nil(t, n.Child) + assert.Nil(t, n.InlineChild) + }) + + t.Run("applies defaults after unmarshaling nested JSON", func(t *testing.T) { + input := `{"child": {"stringField": "from-child"}, "inlineChild": {}}` + var n NestedDefaults + err := json.Unmarshal([]byte(input), &n) + require.NoError(t, err) + + n.ApplyDefaults() + + // Parent defaults + assert.Equal(t, "parent", *n.Name) + + // Child - one field from JSON, others from defaults + assert.Equal(t, "from-child", *n.Child.StringField) + assert.Equal(t, 42, *n.Child.IntField) + + // Inline child - all defaults + assert.Equal(t, "inline-default", *n.InlineChild.Label) + assert.Equal(t, 100, *n.InlineChild.Value) + }) +} + +// TestMapWithDefaults tests ApplyDefaults on structs with additionalProperties +func TestMapWithDefaults(t *testing.T) { + t.Run("applies defaults to known fields", func(t *testing.T) { + m := MapWithDefaults{} + m.ApplyDefaults() + + require.NotNil(t, m.Prefix) + assert.Equal(t, "map-", *m.Prefix) + }) + + t.Run("does not affect additional properties", func(t *testing.T) { + m := MapWithDefaults{ + AdditionalProperties: map[string]string{ + "extra": "value", + }, + } + m.ApplyDefaults() + + assert.Equal(t, "map-", *m.Prefix) + assert.Equal(t, "value", m.AdditionalProperties["extra"]) + }) +} + +// TestArrayDefaults tests ApplyDefaults on structs with array fields +func TestArrayDefaults(t *testing.T) { + t.Run("applies defaults to non-array fields", func(t *testing.T) { + a := ArrayDefaults{} + a.ApplyDefaults() + + require.NotNil(t, a.Count) + assert.Equal(t, 0, *a.Count) + // Array field is not touched (no default generation for arrays currently) + assert.Nil(t, a.Items) + }) +} + +// TestAnyOfWithDefaults tests ApplyDefaults on anyOf variant members +func TestAnyOfWithDefaults(t *testing.T) { + t.Run("applies defaults to anyOf variant 0", func(t *testing.T) { + v0 := AnyOfWithDefaultsValueAnyOf0{} + v0.ApplyDefaults() + + require.NotNil(t, v0.StringVal) + assert.Equal(t, "default-string", *v0.StringVal) + }) + + t.Run("applies defaults to anyOf variant 1", func(t *testing.T) { + v1 := AnyOfWithDefaultsValueAnyOf1{} + v1.ApplyDefaults() + + require.NotNil(t, v1.IntVal) + assert.Equal(t, 999, *v1.IntVal) + }) +} + +// TestOneOfWithDefaults tests ApplyDefaults on oneOf variant members +func TestOneOfWithDefaults(t *testing.T) { + t.Run("applies defaults to oneOf variant 0", func(t *testing.T) { + v0 := OneOfWithDefaultsVariantOneOf0{} + v0.ApplyDefaults() + + require.NotNil(t, v0.OptionA) + assert.Equal(t, "option-a-default", *v0.OptionA) + }) + + t.Run("applies defaults to oneOf variant 1", func(t *testing.T) { + v1 := OneOfWithDefaultsVariantOneOf1{} + v1.ApplyDefaults() + + require.NotNil(t, v1.OptionB) + assert.Equal(t, 123, *v1.OptionB) + }) +} + +// TestAllOfWithDefaults tests ApplyDefaults on allOf merged structs +func TestAllOfWithDefaults(t *testing.T) { + t.Run("applies defaults from all merged schemas", func(t *testing.T) { + a := AllOfWithDefaults{} + a.ApplyDefaults() + + // Default from allOf/0 + require.NotNil(t, a.Base) + assert.Equal(t, "base-value", *a.Base) + + // Default from allOf/1 + require.NotNil(t, a.Extended) + assert.Equal(t, 50, *a.Extended) + }) +} + +// TestDeepNesting tests ApplyDefaults recursion through multiple levels +func TestDeepNesting(t *testing.T) { + t.Run("recurses through all levels", func(t *testing.T) { + d := DeepNesting{ + Level1: &DeepNestingLevel1{ + Level2: &DeepNestingLevel1Level2{ + Level3: &DeepNestingLevel1Level2Level3{}, + }, + }, + } + d.ApplyDefaults() + + // Level 1 defaults + require.NotNil(t, d.Level1.Name) + assert.Equal(t, "level1-name", *d.Level1.Name) + + // Level 2 defaults + require.NotNil(t, d.Level1.Level2.Count) + assert.Equal(t, 2, *d.Level1.Level2.Count) + + // Level 3 defaults + require.NotNil(t, d.Level1.Level2.Level3.Enabled) + assert.Equal(t, false, *d.Level1.Level2.Level3.Enabled) + }) + + t.Run("stops at nil levels", func(t *testing.T) { + d := DeepNesting{ + Level1: &DeepNestingLevel1{ + // Level2 is nil + }, + } + d.ApplyDefaults() + + assert.Equal(t, "level1-name", *d.Level1.Name) + assert.Nil(t, d.Level1.Level2) + }) +} + +// TestRequiredAndOptional tests ApplyDefaults behavior with required fields +func TestRequiredAndOptional(t *testing.T) { + t.Run("applies defaults only to optional pointer fields", func(t *testing.T) { + r := RequiredAndOptional{ + RequiredWithDefault: "set-by-user", + RequiredNoDefault: "also-set", + } + r.ApplyDefaults() + + // Required fields are value types, not pointers, so they don't get defaults applied + assert.Equal(t, "set-by-user", r.RequiredWithDefault) + assert.Equal(t, "also-set", r.RequiredNoDefault) + + // Optional fields with defaults get defaults applied + require.NotNil(t, r.OptionalWithDefault) + assert.Equal(t, "optional-default", *r.OptionalWithDefault) + + // Optional fields without defaults stay nil + assert.Nil(t, r.OptionalNoDefault) + }) +} + +// TestApplyDefaultsIdempotent tests that ApplyDefaults can be called multiple times +func TestApplyDefaultsIdempotent(t *testing.T) { + t.Run("multiple calls have same effect", func(t *testing.T) { + s := SimpleDefaults{} + s.ApplyDefaults() + s.ApplyDefaults() + s.ApplyDefaults() + + assert.Equal(t, "hello", *s.StringField) + assert.Equal(t, 42, *s.IntField) + }) +} + +// TestApplyDefaultsChain tests typical usage pattern: unmarshal then apply defaults +func TestApplyDefaultsChain(t *testing.T) { + t.Run("unmarshal partial JSON then apply defaults", func(t *testing.T) { + input := `{ + "level1": { + "level2": { + "level3": {} + } + } + }` + + var d DeepNesting + err := json.Unmarshal([]byte(input), &d) + require.NoError(t, err) + + d.ApplyDefaults() + + // All defaults applied at all levels + assert.Equal(t, "level1-name", *d.Level1.Name) + assert.Equal(t, 2, *d.Level1.Level2.Count) + assert.Equal(t, false, *d.Level1.Level2.Level3.Enabled) + }) +} diff --git a/experimental/internal/codegen/test/external_ref/config.yaml b/experimental/internal/codegen/test/external_ref/config.yaml new file mode 100644 index 0000000000..919d5b9d47 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/config.yaml @@ -0,0 +1,5 @@ +package: externalref +output: internal/codegen/test/external_ref/spec.gen.go +import-mapping: + ./packagea/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea + ./packageb/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb diff --git a/experimental/internal/codegen/test/external_ref/external_ref_test.go b/experimental/internal/codegen/test/external_ref/external_ref_test.go new file mode 100644 index 0000000000..885ddb05bb --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/external_ref_test.go @@ -0,0 +1,62 @@ +package externalref + +import ( + "testing" + + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea" + "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" +) + +// TestCrossPackageReferences verifies that types from external packages +// can be used correctly in the Container type. +func TestCrossPackageReferences(t *testing.T) { + // Create objects from each package + name := "test-name" + b := &packageb.ObjectB{ + Name: &name, + } + + a := &packagea.ObjectA{ + Name: &name, + ObjectB: b, + } + + // Create container that references both + container := Container{ + ObjectA: a, + ObjectB: b, + } + + // Verify the structure + if container.ObjectA == nil { + t.Error("ObjectA should not be nil") + } + if container.ObjectB == nil { + t.Error("ObjectB should not be nil") + } + if *container.ObjectA.Name != "test-name" { + t.Errorf("ObjectA.Name = %q, want %q", *container.ObjectA.Name, "test-name") + } + if *container.ObjectB.Name != "test-name" { + t.Errorf("ObjectB.Name = %q, want %q", *container.ObjectB.Name, "test-name") + } + + // Verify nested reference in ObjectA + if container.ObjectA.ObjectB == nil { + t.Error("ObjectA.ObjectB should not be nil") + } + if *container.ObjectA.ObjectB.Name != "test-name" { + t.Errorf("ObjectA.ObjectB.Name = %q, want %q", *container.ObjectA.ObjectB.Name, "test-name") + } +} + +// TestApplyDefaults verifies that ApplyDefaults works across package boundaries. +func TestApplyDefaults(t *testing.T) { + container := Container{ + ObjectA: &packagea.ObjectA{}, + ObjectB: &packageb.ObjectB{}, + } + + // Should not panic when calling ApplyDefaults across packages + container.ApplyDefaults() +} diff --git a/experimental/internal/codegen/test/external_ref/packagea/config.yaml b/experimental/internal/codegen/test/external_ref/packagea/config.yaml new file mode 100644 index 0000000000..7cacfcb822 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packagea/config.yaml @@ -0,0 +1,4 @@ +package: packagea +output: internal/codegen/test/external_ref/packagea/spec.gen.go +import-mapping: + ../packageb/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb diff --git a/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go b/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go new file mode 100644 index 0000000000..b865bfb69d --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go @@ -0,0 +1,22 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package packagea + +import ( + ext_a5fddf6c "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" +) + +// #/components/schemas/ObjectA +type ObjectASchemaComponent struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` + ObjectB *ext_a5fddf6c.ObjectB `json:"object_b,omitempty" form:"object_b,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectASchemaComponent) ApplyDefaults() { + if s.ObjectB != nil { + s.ObjectB.ApplyDefaults() + } +} + +type ObjectA = ObjectASchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/packagea/spec.yaml b/experimental/internal/codegen/test/external_ref/packagea/spec.yaml new file mode 100644 index 0000000000..77f3ea45f5 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packagea/spec.yaml @@ -0,0 +1,14 @@ +openapi: "3.1.0" +info: + title: Package A + version: "1.0" +paths: {} +components: + schemas: + ObjectA: + type: object + properties: + name: + type: string + object_b: + $ref: ../packageb/spec.yaml#/components/schemas/ObjectB diff --git a/experimental/internal/codegen/test/external_ref/packageb/config.yaml b/experimental/internal/codegen/test/external_ref/packageb/config.yaml new file mode 100644 index 0000000000..7b36e2c291 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packageb/config.yaml @@ -0,0 +1,2 @@ +package: packageb +output: internal/codegen/test/external_ref/packageb/spec.gen.go diff --git a/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go b/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go new file mode 100644 index 0000000000..e72bf4ac99 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go @@ -0,0 +1,14 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package packageb + +// #/components/schemas/ObjectB +type ObjectBSchemaComponent struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectBSchemaComponent) ApplyDefaults() { +} + +type ObjectB = ObjectBSchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/packageb/spec.yaml b/experimental/internal/codegen/test/external_ref/packageb/spec.yaml new file mode 100644 index 0000000000..bf9af943f5 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/packageb/spec.yaml @@ -0,0 +1,12 @@ +openapi: "3.1.0" +info: + title: Package B + version: "1.0" +paths: {} +components: + schemas: + ObjectB: + type: object + properties: + name: + type: string diff --git a/experimental/internal/codegen/test/external_ref/spec.gen.go b/experimental/internal/codegen/test/external_ref/spec.gen.go new file mode 100644 index 0000000000..cf179d426b --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/spec.gen.go @@ -0,0 +1,26 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package externalref + +import ( + ext_95d82e90 "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea" + ext_a5fddf6c "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" +) + +// #/components/schemas/Container +type ContainerSchemaComponent struct { + ObjectA *ext_95d82e90.ObjectA `json:"object_a,omitempty" form:"object_a,omitempty"` + ObjectB *ext_a5fddf6c.ObjectB `json:"object_b,omitempty" form:"object_b,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ContainerSchemaComponent) ApplyDefaults() { + if s.ObjectA != nil { + s.ObjectA.ApplyDefaults() + } + if s.ObjectB != nil { + s.ObjectB.ApplyDefaults() + } +} + +type Container = ContainerSchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/spec.yaml b/experimental/internal/codegen/test/external_ref/spec.yaml new file mode 100644 index 0000000000..5a8e0ada72 --- /dev/null +++ b/experimental/internal/codegen/test/external_ref/spec.yaml @@ -0,0 +1,14 @@ +openapi: "3.1.0" +info: + title: External Ref Test + version: "1.0" +paths: {} +components: + schemas: + Container: + type: object + properties: + object_a: + $ref: ./packagea/spec.yaml#/components/schemas/ObjectA + object_b: + $ref: ./packageb/spec.yaml#/components/schemas/ObjectB diff --git a/experimental/internal/codegen/test/files/comprehensive.yaml b/experimental/internal/codegen/test/files/comprehensive.yaml new file mode 100644 index 0000000000..7bdef74eea --- /dev/null +++ b/experimental/internal/codegen/test/files/comprehensive.yaml @@ -0,0 +1,861 @@ +openapi: "3.1.0" +info: + title: Comprehensive Test Schema + version: "1.0.0" + description: Tests all schema patterns for oapi-codegen + +paths: + /simple: + get: + operationId: getSimple + responses: + "200": + description: Simple response + content: + application/json: + schema: + $ref: "#/components/schemas/SimpleObject" + + /inline-response: + get: + operationId: getInlineResponse + responses: + "200": + description: Inline object in response + content: + application/json: + schema: + type: object + required: + - id + - name + properties: + id: + type: integer + name: + type: string + + /parameters/{pathParam}: + parameters: + - name: pathParam + in: path + required: true + schema: + type: string + format: uuid + get: + operationId: getWithParameters + parameters: + - name: queryString + in: query + schema: + type: string + - name: queryInt + in: query + schema: + type: integer + - name: queryArray + in: query + schema: + type: array + items: + type: string + - name: headerParam + in: header + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/SimpleObject" + + /request-body: + post: + operationId: postRequestBody + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/AllTypesRequired" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/SimpleObject" + + /multi-content: + post: + operationId: postMultiContent + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SimpleObject" + application/x-www-form-urlencoded: + schema: + $ref: "#/components/schemas/SimpleObject" + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + metadata: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/SimpleObject" + text/plain: + schema: + type: string + +components: + schemas: + # =========================================== + # PRIMITIVE TYPES - All formats + # =========================================== + + AllTypesRequired: + type: object + required: + - intField + - int32Field + - int64Field + - floatField + - doubleField + - numberField + - stringField + - boolField + - dateField + - dateTimeField + - uuidField + - emailField + - uriField + - hostnameField + - ipv4Field + - ipv6Field + - byteField + - binaryField + - passwordField + properties: + intField: + type: integer + int32Field: + type: integer + format: int32 + int64Field: + type: integer + format: int64 + floatField: + type: number + format: float + doubleField: + type: number + format: double + numberField: + type: number + stringField: + type: string + boolField: + type: boolean + dateField: + type: string + format: date + dateTimeField: + type: string + format: date-time + uuidField: + type: string + format: uuid + emailField: + type: string + format: email + uriField: + type: string + format: uri + hostnameField: + type: string + format: hostname + ipv4Field: + type: string + format: ipv4 + ipv6Field: + type: string + format: ipv6 + byteField: + type: string + format: byte + binaryField: + type: string + format: binary + passwordField: + type: string + format: password + + AllTypesOptional: + type: object + properties: + intField: + type: integer + int32Field: + type: integer + format: int32 + int64Field: + type: integer + format: int64 + floatField: + type: number + format: float + doubleField: + type: number + format: double + numberField: + type: number + stringField: + type: string + boolField: + type: boolean + dateField: + type: string + format: date + dateTimeField: + type: string + format: date-time + uuidField: + type: string + format: uuid + emailField: + type: string + format: email + + # =========================================== + # NULLABLE TYPES + # =========================================== + + NullableRequired: + type: object + required: + - nullableString + - nullableInt + - nullableObject + properties: + nullableString: + type: + - string + - "null" + nullableInt: + type: + - integer + - "null" + nullableObject: + type: + - object + - "null" + properties: + name: + type: string + + NullableOptional: + type: object + properties: + nullableString: + type: + - string + - "null" + nullableInt: + type: + - integer + - "null" + + # =========================================== + # ARRAYS + # =========================================== + + ArrayTypes: + type: object + properties: + stringArray: + type: array + items: + type: string + intArray: + type: array + items: + type: integer + objectArray: + type: array + items: + $ref: "#/components/schemas/SimpleObject" + inlineObjectArray: + type: array + items: + type: object + properties: + id: + type: integer + name: + type: string + nestedArray: + type: array + items: + type: array + items: + type: string + nullableArray: + type: + - array + - "null" + items: + type: string + arrayWithConstraints: + type: array + minItems: 1 + maxItems: 10 + items: + type: string + + # =========================================== + # OBJECTS + # =========================================== + + SimpleObject: + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + + NestedObject: + type: object + properties: + outer: + type: object + properties: + inner: + type: object + properties: + value: + type: string + + # =========================================== + # ADDITIONAL PROPERTIES + # =========================================== + + AdditionalPropsAny: + type: object + additionalProperties: true + + AdditionalPropsNone: + type: object + additionalProperties: false + properties: + known: + type: string + + AdditionalPropsTyped: + type: object + additionalProperties: + type: integer + + AdditionalPropsObject: + type: object + additionalProperties: + $ref: "#/components/schemas/SimpleObject" + + AdditionalPropsWithProps: + type: object + properties: + id: + type: integer + additionalProperties: + type: string + + # =========================================== + # ENUMS + # =========================================== + + StringEnum: + type: string + enum: + - value1 + - value2 + - value3 + + IntegerEnum: + type: integer + enum: + - 1 + - 2 + - 3 + + ObjectWithEnum: + type: object + properties: + status: + type: string + enum: + - pending + - active + - completed + priority: + type: integer + enum: + - 1 + - 2 + - 3 + + InlineEnumInProperty: + type: object + properties: + inlineStatus: + type: string + enum: + - on + - off + + # =========================================== + # ALLOF - Inheritance/Composition + # =========================================== + + BaseProperties: + type: object + properties: + id: + type: integer + createdAt: + type: string + format: date-time + + ExtendedObject: + allOf: + - $ref: "#/components/schemas/BaseProperties" + - type: object + required: + - name + properties: + name: + type: string + description: + type: string + + DeepInheritance: + allOf: + - $ref: "#/components/schemas/ExtendedObject" + - type: object + properties: + extra: + type: string + + AllOfMultipleRefs: + allOf: + - $ref: "#/components/schemas/BaseProperties" + - $ref: "#/components/schemas/SimpleObject" + - type: object + properties: + merged: + type: boolean + + AllOfInlineOnly: + allOf: + - type: object + properties: + first: + type: string + - type: object + properties: + second: + type: integer + + # =========================================== + # ANYOF - Union Types + # =========================================== + + AnyOfPrimitives: + anyOf: + - type: string + - type: integer + + AnyOfObjects: + anyOf: + - $ref: "#/components/schemas/SimpleObject" + - $ref: "#/components/schemas/BaseProperties" + + AnyOfMixed: + anyOf: + - type: string + - $ref: "#/components/schemas/SimpleObject" + - type: object + properties: + inline: + type: boolean + + AnyOfNullable: + anyOf: + - type: string + - type: "null" + + ObjectWithAnyOfProperty: + type: object + properties: + value: + anyOf: + - type: string + - type: integer + - type: boolean + + ArrayOfAnyOf: + type: array + items: + anyOf: + - $ref: "#/components/schemas/SimpleObject" + - $ref: "#/components/schemas/BaseProperties" + + # =========================================== + # ONEOF - Discriminated Unions + # =========================================== + + OneOfSimple: + oneOf: + - $ref: "#/components/schemas/SimpleObject" + - $ref: "#/components/schemas/BaseProperties" + + OneOfWithDiscriminator: + oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + discriminator: + propertyName: petType + + OneOfWithDiscriminatorMapping: + oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + discriminator: + propertyName: petType + mapping: + cat: "#/components/schemas/Cat" + dog: "#/components/schemas/Dog" + + Cat: + type: object + required: + - petType + - meow + properties: + petType: + type: string + meow: + type: string + whiskerLength: + type: number + + Dog: + type: object + required: + - petType + - bark + properties: + petType: + type: string + bark: + type: string + tailLength: + type: number + + OneOfInline: + oneOf: + - type: object + properties: + optionA: + type: string + - type: object + properties: + optionB: + type: integer + + OneOfPrimitives: + oneOf: + - type: string + - type: number + - type: boolean + + ObjectWithOneOfProperty: + type: object + properties: + id: + type: integer + variant: + oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + discriminator: + propertyName: petType + + # =========================================== + # COMBINED COMPOSITION + # =========================================== + + AllOfWithOneOf: + allOf: + - $ref: "#/components/schemas/BaseProperties" + - oneOf: + - $ref: "#/components/schemas/Cat" + - $ref: "#/components/schemas/Dog" + discriminator: + propertyName: petType + + OneOfWithAllOf: + oneOf: + - allOf: + - $ref: "#/components/schemas/BaseProperties" + - type: object + properties: + variant: + type: string + const: "a" + - allOf: + - $ref: "#/components/schemas/BaseProperties" + - type: object + properties: + variant: + type: string + const: "b" + + # =========================================== + # RECURSIVE TYPES + # =========================================== + + TreeNode: + type: object + properties: + value: + type: string + children: + type: array + items: + $ref: "#/components/schemas/TreeNode" + + LinkedListNode: + type: object + properties: + value: + type: integer + next: + $ref: "#/components/schemas/LinkedListNode" + + RecursiveOneOf: + oneOf: + - type: string + - type: object + properties: + nested: + $ref: "#/components/schemas/RecursiveOneOf" + + # =========================================== + # READ/WRITE ONLY + # =========================================== + + ReadWriteOnly: + type: object + required: + - id + - password + properties: + id: + type: integer + readOnly: true + password: + type: string + writeOnly: true + name: + type: string + + # =========================================== + # DEFAULTS AND CONST + # =========================================== + + WithDefaults: + type: object + properties: + stringWithDefault: + type: string + default: "default_value" + intWithDefault: + type: integer + default: 42 + boolWithDefault: + type: boolean + default: true + arrayWithDefault: + type: array + items: + type: string + default: [] + + WithConst: + type: object + properties: + version: + type: string + const: "1.0.0" + type: + type: string + const: "fixed" + + # =========================================== + # CONSTRAINTS + # =========================================== + + WithConstraints: + type: object + properties: + boundedInt: + type: integer + minimum: 0 + maximum: 100 + exclusiveBoundedInt: + type: integer + exclusiveMinimum: 0 + exclusiveMaximum: 100 + multipleOf: + type: integer + multipleOf: 5 + boundedString: + type: string + minLength: 1 + maxLength: 255 + patternString: + type: string + pattern: "^[a-z]+$" + boundedArray: + type: array + minItems: 1 + maxItems: 10 + items: + type: string + uniqueArray: + type: array + uniqueItems: true + items: + type: string + + # =========================================== + # OPENAPI 3.1 SPECIFIC + # =========================================== + + TypeArray31: + type: + - object + - "null" + properties: + name: + type: string + + PrefixItems31: + type: array + prefixItems: + - type: string + - type: integer + - type: boolean + items: + type: string + + # =========================================== + # EMPTY / ANY TYPE + # =========================================== + + EmptySchema: {} + + AnyValue: + description: Accepts any JSON value + + ExplicitAny: + type: + - string + - number + - integer + - boolean + - array + - object + - "null" + + # =========================================== + # COMPLEX NESTED STRUCTURES + # =========================================== + + ComplexNested: + type: object + properties: + metadata: + type: object + additionalProperties: + anyOf: + - type: string + - type: integer + - type: array + items: + type: string + items: + type: array + items: + allOf: + - $ref: "#/components/schemas/BaseProperties" + - type: object + properties: + tags: + type: array + items: + type: string + config: + oneOf: + - type: object + properties: + mode: + type: string + const: "simple" + value: + type: string + - type: object + properties: + mode: + type: string + const: "advanced" + options: + type: object + additionalProperties: + type: string + + # =========================================== + # MAPS + # =========================================== + + StringMap: + type: object + additionalProperties: + type: string + + ObjectMap: + type: object + additionalProperties: + $ref: "#/components/schemas/SimpleObject" + + NestedMap: + type: object + additionalProperties: + type: object + additionalProperties: + type: string diff --git a/experimental/internal/codegen/test/issues/issue_1029/doc.go b/experimental/internal/codegen/test/issues/issue_1029/doc.go new file mode 100644 index 0000000000..dd7dc0eb30 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1029/doc.go @@ -0,0 +1,5 @@ +// Package issue_1029 tests that oneOf with multiple single-value string enums generates valid code. +// https://github.com/oapi-codegen/oapi-codegen/issues/1029 +package issue_1029 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go new file mode 100644 index 0000000000..7c5a5d2fa1 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go @@ -0,0 +1,186 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Registration +type Registration struct { + State *RegistrationState `json:"state,omitempty" form:"state,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Registration) ApplyDefaults() { +} + +// #/components/schemas/Registration/properties/state +type RegistrationState struct { + RegistrationStateOneOf0 *RegistrationStateOneOf0 + RegistrationStateOneOf1 *RegistrationStateOneOf1 + RegistrationStateOneOf2 *RegistrationStateOneOf2 + RegistrationStateOneOf3 *RegistrationStateOneOf3 +} + +func (u RegistrationState) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.RegistrationStateOneOf0 != nil { + count++ + data, err = json.Marshal(u.RegistrationStateOneOf0) + if err != nil { + return nil, err + } + } + if u.RegistrationStateOneOf1 != nil { + count++ + data, err = json.Marshal(u.RegistrationStateOneOf1) + if err != nil { + return nil, err + } + } + if u.RegistrationStateOneOf2 != nil { + count++ + data, err = json.Marshal(u.RegistrationStateOneOf2) + if err != nil { + return nil, err + } + } + if u.RegistrationStateOneOf3 != nil { + count++ + data, err = json.Marshal(u.RegistrationStateOneOf3) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("RegistrationState: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *RegistrationState) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 RegistrationStateOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.RegistrationStateOneOf0 = &v0 + successCount++ + } + + var v1 RegistrationStateOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.RegistrationStateOneOf1 = &v1 + successCount++ + } + + var v2 RegistrationStateOneOf2 + if err := json.Unmarshal(data, &v2); err == nil { + u.RegistrationStateOneOf2 = &v2 + successCount++ + } + + var v3 RegistrationStateOneOf3 + if err := json.Unmarshal(data, &v3); err == nil { + u.RegistrationStateOneOf3 = &v3 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("RegistrationState: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *RegistrationState) ApplyDefaults() { +} + +// #/components/schemas/Registration/properties/state/oneOf/0 +type RegistrationStateOneOf0 string + +const ( + RegistrationStateOneOf0_undefined RegistrationStateOneOf0 = "undefined" +) + +// #/components/schemas/Registration/properties/state/oneOf/1 +type RegistrationStateOneOf1 string + +const ( + RegistrationStateOneOf1_registered RegistrationStateOneOf1 = "registered" +) + +// #/components/schemas/Registration/properties/state/oneOf/2 +type RegistrationStateOneOf2 string + +const ( + RegistrationStateOneOf2_pending RegistrationStateOneOf2 = "pending" +) + +// #/components/schemas/Registration/properties/state/oneOf/3 +type RegistrationStateOneOf3 string + +const ( + RegistrationStateOneOf3_active RegistrationStateOneOf3 = "active" +) + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/6yQzY7UMBCE736KknJlMrPsibwBJySExNmb1CQNjm2527MaId4dOeFnZw4Iob25q7vr", + "a1eH96qVeDi9fTcgRX44Q61InMFYV8XZS2iVJcyMLN6IXFJmCVfXYTHLOhyPs9hSn/oxrcfksxzGNHFm", + "vC2kofTYWK5zHT4vjKja7Hfys9iCtQaTHIjWCDxcfKi8OeqN62ALfx80oRGgS6qhvdcsgfBxwnMqXzGm", + "UjhauPYuZUafZcBjf+ofncRzGhxgYoHDiyjwiWoOuLCopDjgoT/1J5e9LTrg23fXICkymrZ9HReufnsC", + "HzmLWvHWFjcFsGvmgPT0haP9lPYQTai/hgA1b/xTYo/lpQActgxutV2vceJZIqe73g7fA/xHq7L9geU1", + "vDLjdD/9X0Z+NLnwbz4/AgAA//+mSD78zgIAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go new file mode 100644 index 0000000000..4ea2eabfbe --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go @@ -0,0 +1,89 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestRegistrationStateOneOfEnums verifies that oneOf with string enums generates +// correctly with proper enum constants. +// https://github.com/oapi-codegen/oapi-codegen/issues/1029 +func TestRegistrationStateOneOfEnums(t *testing.T) { + // Verify enum constants exist and have correct values + tests := []struct { + name string + enum RegistrationStateOneOf0 + value string + }{ + {"undefined", RegistrationStateOneOf0_undefined, "undefined"}, + } + + for _, tt := range tests { + if string(tt.enum) != tt.value { + t.Errorf("%s enum = %q, want %q", tt.name, tt.enum, tt.value) + } + } +} + +func TestRegistrationStateMarshal(t *testing.T) { + // Test serialization of oneOf with string enum + state := RegistrationState{ + RegistrationStateOneOf0: ptrTo(RegistrationStateOneOf0(RegistrationStateOneOf0_undefined)), + } + + reg := Registration{ + State: &state, + } + + data, err := json.Marshal(reg) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + // Verify the JSON contains the expected value + expected := `{"state":"undefined"}` + if string(data) != expected { + t.Errorf("Marshal result = %s, want %s", string(data), expected) + } +} + +func TestRegistrationStateUnmarshalLimitation(t *testing.T) { + // Note: Unmarshaling oneOf with multiple string enum types is inherently + // ambiguous without a discriminator, since any string can match any of the + // enum types. This test documents that limitation. + input := `{"state":"undefined"}` + + var decoded Registration + err := json.Unmarshal([]byte(input), &decoded) + + // The error is expected because all 4 string enum types can unmarshal + // from the same string value + if err == nil { + t.Log("Unmarshal succeeded (all variants matched)") + } else { + t.Logf("Unmarshal failed as expected for ambiguous oneOf: %v", err) + } +} + +func TestAllEnumConstants(t *testing.T) { + // Verify all enum constants are defined + _ = RegistrationStateOneOf0_undefined + _ = RegistrationStateOneOf1_registered + _ = RegistrationStateOneOf2_pending + _ = RegistrationStateOneOf3_active + + // Test values + if string(RegistrationStateOneOf1_registered) != "registered" { + t.Error("registered enum has wrong value") + } + if string(RegistrationStateOneOf2_pending) != "pending" { + t.Error("pending enum has wrong value") + } + if string(RegistrationStateOneOf3_active) != "active" { + t.Error("active enum has wrong value") + } +} + +func ptrTo[T any](v T) *T { + return &v +} diff --git a/experimental/internal/codegen/test/issues/issue_1029/spec.yaml b/experimental/internal/codegen/test/issues/issue_1029/spec.yaml new file mode 100644 index 0000000000..698973cfbb --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1029/spec.yaml @@ -0,0 +1,29 @@ +# Issue 1029: oneOf string enums failing to generate properly +# https://github.com/oapi-codegen/oapi-codegen/issues/1029 +# +# When using oneOf with multiple single-value string enums, +# the generated code should compile and work correctly. +openapi: 3.0.3 +info: + title: Issue 1029 Test + version: 1.0.0 +paths: {} +components: + schemas: + Registration: + type: object + properties: + state: + oneOf: + - enum: + - undefined + type: string + - enum: + - registered + type: string + - enum: + - pending + type: string + - enum: + - active + type: string diff --git a/experimental/internal/codegen/test/issues/issue_1039/doc.go b/experimental/internal/codegen/test/issues/issue_1039/doc.go new file mode 100644 index 0000000000..64016470f8 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1039/doc.go @@ -0,0 +1,5 @@ +// Package issue_1039 tests nullable type generation. +// https://github.com/oapi-codegen/oapi-codegen/issues/1039 +package issue_1039 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go new file mode 100644 index 0000000000..d996cfb752 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go @@ -0,0 +1,291 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/PatchRequest +// A request to patch an existing user object. +type PatchRequest struct { + SimpleRequiredNullable SimpleRequiredNullable `json:"simple_required_nullable" form:"simple_required_nullable"` + SimpleOptionalNullable SimpleOptionalNullable `json:"simple_optional_nullable,omitempty" form:"simple_optional_nullable,omitempty"` + SimpleOptionalNonNullable *any `json:"simple_optional_non_nullable,omitempty" form:"simple_optional_non_nullable,omitempty"` + ComplexRequiredNullable Nullable[ComplexRequiredNullable] `json:"complex_required_nullable" form:"complex_required_nullable"` + ComplexOptionalNullable Nullable[ComplexOptionalNullable] `json:"complex_optional_nullable,omitempty" form:"complex_optional_nullable,omitempty"` + AdditionalProperties map[string]any `json:"-"` +} + +func (s PatchRequest) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + result["simple_required_nullable"] = s.SimpleRequiredNullable + result["simple_optional_nullable"] = s.SimpleOptionalNullable + if s.SimpleOptionalNonNullable != nil { + result["simple_optional_non_nullable"] = s.SimpleOptionalNonNullable + } + result["complex_required_nullable"] = s.ComplexRequiredNullable + result["complex_optional_nullable"] = s.ComplexOptionalNullable + + // Add additional properties + for k, v := range s.AdditionalProperties { + result[k] = v + } + + return json.Marshal(result) +} + +func (s *PatchRequest) UnmarshalJSON(data []byte) error { + // Known fields + knownFields := map[string]bool{ + "simple_required_nullable": true, + "simple_optional_nullable": true, + "simple_optional_non_nullable": true, + "complex_required_nullable": true, + "complex_optional_nullable": true, + } + + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["simple_required_nullable"]; ok { + if err := json.Unmarshal(v, &s.SimpleRequiredNullable); err != nil { + return err + } + } + if v, ok := raw["simple_optional_nullable"]; ok { + if err := json.Unmarshal(v, &s.SimpleOptionalNullable); err != nil { + return err + } + } + if v, ok := raw["simple_optional_non_nullable"]; ok { + var val any + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.SimpleOptionalNonNullable = &val + } + if v, ok := raw["complex_required_nullable"]; ok { + if err := json.Unmarshal(v, &s.ComplexRequiredNullable); err != nil { + return err + } + } + if v, ok := raw["complex_optional_nullable"]; ok { + if err := json.Unmarshal(v, &s.ComplexOptionalNullable); err != nil { + return err + } + } + + // Collect additional properties + s.AdditionalProperties = make(map[string]any) + for k, v := range raw { + if !knownFields[k] { + var val any + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.AdditionalProperties[k] = val + } + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *PatchRequest) ApplyDefaults() { +} + +// #/components/schemas/simple_required_nullable +// Simple required and nullable +type SimpleRequiredNullable = Nullable[int] + +// #/components/schemas/simple_optional_nullable +// Simple optional and nullable +type SimpleOptionalNullable = Nullable[int] + +// #/components/schemas/complex_required_nullable +// Complex required and nullable +type ComplexRequiredNullable struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` // Optional and non nullable +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexRequiredNullable) ApplyDefaults() { +} + +// #/components/schemas/complex_optional_nullable +// Complex, optional and nullable +type ComplexOptionalNullable struct { + AliasName Nullable[string] `json:"alias_name,omitempty" form:"alias_name,omitempty"` // Optional and nullable + Name *string `json:"name,omitempty" form:"name,omitempty"` // Optional and non nullable +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ComplexOptionalNullable) ApplyDefaults() { +} + +// Nullable is a generic type that can distinguish between: +// - Field not provided (unspecified) +// - Field explicitly set to null +// - Field has a value +// +// This is implemented as a map[bool]T where: +// - Empty map: unspecified +// - map[false]T: explicitly null +// - map[true]T: has a value +type Nullable[T any] map[bool]T + +// NewNullableWithValue creates a Nullable with the given value. +func NewNullableWithValue[T any](value T) Nullable[T] { + return Nullable[T]{true: value} +} + +// NewNullNullable creates a Nullable that is explicitly null. +func NewNullNullable[T any]() Nullable[T] { + return Nullable[T]{false: *new(T)} +} + +// Get returns the value if set, or an error if null or unspecified. +func (n Nullable[T]) Get() (T, error) { + if v, ok := n[true]; ok { + return v, nil + } + var zero T + if n.IsNull() { + return zero, ErrNullableIsNull + } + return zero, ErrNullableNotSpecified +} + +// MustGet returns the value or panics if null or unspecified. +func (n Nullable[T]) MustGet() T { + v, err := n.Get() + if err != nil { + panic(err) + } + return v +} + +// Set assigns a value. +func (n *Nullable[T]) Set(value T) { + *n = Nullable[T]{true: value} +} + +// SetNull marks the field as explicitly null. +func (n *Nullable[T]) SetNull() { + *n = Nullable[T]{false: *new(T)} +} + +// SetUnspecified clears the field (as if it was never set). +func (n *Nullable[T]) SetUnspecified() { + *n = nil +} + +// IsNull returns true if the field is explicitly null. +func (n Nullable[T]) IsNull() bool { + if n == nil { + return false + } + _, ok := n[false] + return ok +} + +// IsSpecified returns true if the field was provided (either null or a value). +func (n Nullable[T]) IsSpecified() bool { + return len(n) > 0 +} + +// MarshalJSON implements json.Marshaler. +func (n Nullable[T]) MarshalJSON() ([]byte, error) { + if n.IsNull() { + return []byte("null"), nil + } + if v, ok := n[true]; ok { + return json.Marshal(v) + } + // Unspecified - this shouldn't be called if omitempty is used correctly + return []byte("null"), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *Nullable[T]) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + n.SetNull() + return nil + } + var v T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + n.Set(v) + return nil +} + +// ErrNullableIsNull is returned when trying to get a value from a null Nullable. +var ErrNullableIsNull = errors.New("nullable value is null") + +// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. +var ErrNullableNotSpecified = errors.New("nullable value is not specified") + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/7RUTY/TMBC9+1eMEqReaNNlT+QGnFYIdgXcKzeZJl5S23gmqJX48SjfSZu0ge7eEnvm", + "vTdvxuPDA1GOcLe+fx/C1zzL5DZD4KNFggQ1OsnKaOFDymwpDIJEcZpvV5HZB0ZatYxMjAnq4Y8qQCko", + "UIUvfPgifyJQ7hA4lQx6yCMdNlwYg3XGosuOwljU0qoQ7lfr1Z1QemdCAfAbHSmjQ1isi/OFAGDFGYaA", + "B7m3GQqAGClyynIZ90cAwP9JsJJTKkiDGjsssazkKK0+AYrQ0qSHuJXwVATU9w5/5Uj80cTHJuVE4I8U", + "K0jYmvjYxhSJymEcArsc2+PIaEbNHRaAtDZTUSkieCaj+3cAFKW4l8MzgDcOdyF4fhCZvTUaNVNQRVJQ", + "yv9W6fbaMsgaTUgd0OLder3o4w6q8h4/e0J06EVgTVDl9FkalKIbIZjtM0YsRkA/NHYCm9ozqQEPiljp", + "BHJCV2evxImLrc4lkCqatGmuNs0w9EIK3RkeJmOqEWHV92MKtm+R3woCqWM4Y77cmCkG71SDKf2S2YSG", + "5voGDWcMFzQYPUuH0ctbtfSYvN6LmejlyzVmkuJcxSu2ZpKiUSHjWFVXT938wk5mhELMGeHqfSrNmKCr", + "z9qY/p4avNrvJeqEwWLO2N7EO26pmDuqFTexUzqZzWL0CdPVIRxZfdcr/FShXpzdsVWl5R4nN/fjZCVd", + "wsAUMWu+r+32upa3F5/AWDEyU5I2/1DSlXK649EGvLR7o1R/AwAA///zkywGmQkAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go new file mode 100644 index 0000000000..f165ca7ce8 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go @@ -0,0 +1,266 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestNullableTypes verifies that nullable types are generated properly. +// https://github.com/oapi-codegen/oapi-codegen/issues/1039 +// +// The implementation uses Nullable[T] for nullable types: +// - Nullable primitive schemas generate type aliases: type SimpleRequiredNullable = Nullable[int] +// - Nullable object fields are wrapped: Nullable[ComplexType] +// - Inline nullable primitives use Nullable[T] directly +func TestNullableTypes(t *testing.T) { + // Create a patch request with various nullable fields + name := "test-name" + + // SimpleRequiredNullable is Nullable[int] + simpleRequired := NewNullableWithValue(42) + + // ComplexRequiredNullable is wrapped in Nullable + complexRequired := NewNullableWithValue(ComplexRequiredNullable{Name: &name}) + + req := PatchRequest{ + SimpleRequiredNullable: simpleRequired, + ComplexRequiredNullable: complexRequired, + } + + // Verify simple nullable value + val, err := req.SimpleRequiredNullable.Get() + if err != nil { + t.Fatalf("SimpleRequiredNullable.Get() failed: %v", err) + } + if val != 42 { + t.Errorf("SimpleRequiredNullable = %v, want 42", val) + } + + // Verify complex nullable can retrieve value + complexVal, err := req.ComplexRequiredNullable.Get() + if err != nil { + t.Fatalf("ComplexRequiredNullable.Get() failed: %v", err) + } + if *complexVal.Name != "test-name" { + t.Errorf("ComplexRequiredNullable.Name = %q, want %q", *complexVal.Name, "test-name") + } +} + +func TestPatchRequestJSONRoundTrip(t *testing.T) { + name := "test" + original := PatchRequest{ + SimpleRequiredNullable: NewNullableWithValue(100), + ComplexRequiredNullable: NewNullableWithValue(ComplexRequiredNullable{Name: &name}), + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + t.Logf("Marshaled: %s", string(data)) + + var decoded PatchRequest + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + // Verify simple nullable round-trips correctly + decodedSimple, err := decoded.SimpleRequiredNullable.Get() + if err != nil { + t.Fatalf("SimpleRequiredNullable.Get() failed: %v", err) + } + if decodedSimple != 100 { + t.Errorf("SimpleRequiredNullable mismatch: got %v, want %v", decodedSimple, 100) + } + + // Verify complex nullable round-trips correctly + complexVal, err := decoded.ComplexRequiredNullable.Get() + if err != nil { + t.Fatalf("ComplexRequiredNullable.Get() failed: %v", err) + } + if *complexVal.Name != "test" { + t.Errorf("ComplexRequiredNullable.Name = %q, want %q", *complexVal.Name, "test") + } +} + +func TestComplexNullableTypes(t *testing.T) { + // Complex nullable types use Nullable[T] + name := "name" + opt := ComplexOptionalNullable{ + AliasName: NewNullableWithValue("alias"), + Name: &name, + } + + req := PatchRequest{ + SimpleRequiredNullable: NewNullNullable[int](), // explicitly null + ComplexRequiredNullable: NewNullNullable[ComplexRequiredNullable](), + ComplexOptionalNullable: NewNullableWithValue(opt), + } + + // Check the complex optional nullable + if !req.ComplexOptionalNullable.IsSpecified() { + t.Fatal("ComplexOptionalNullable should be specified") + } + optVal := req.ComplexOptionalNullable.MustGet() + aliasVal := optVal.AliasName.MustGet() + if aliasVal != "alias" { + t.Errorf("AliasName = %q, want %q", aliasVal, "alias") + } + + // Check that required nullable can be null + if !req.ComplexRequiredNullable.IsNull() { + t.Error("ComplexRequiredNullable should be null") + } + if !req.SimpleRequiredNullable.IsNull() { + t.Error("SimpleRequiredNullable should be null") + } +} + +func TestNullableThreeStates(t *testing.T) { + // Test unspecified (nil/empty map) + unspecified := Nullable[string](nil) + if unspecified.IsSpecified() { + t.Error("unspecified should not be specified") + } + if unspecified.IsNull() { + t.Error("unspecified should not be null") + } + _, err := unspecified.Get() + if err != ErrNullableNotSpecified { + t.Errorf("Get() on unspecified should return ErrNullableNotSpecified, got %v", err) + } + + // Test explicitly null + null := NewNullNullable[string]() + if !null.IsSpecified() { + t.Error("null should be specified") + } + if !null.IsNull() { + t.Error("null should be null") + } + _, err = null.Get() + if err != ErrNullableIsNull { + t.Errorf("Get() on null should return ErrNullableIsNull, got %v", err) + } + + // Test with value + withValue := NewNullableWithValue("hello") + if !withValue.IsSpecified() { + t.Error("withValue should be specified") + } + if withValue.IsNull() { + t.Error("withValue should not be null") + } + val, err := withValue.Get() + if err != nil { + t.Errorf("Get() on withValue should succeed, got %v", err) + } + if val != "hello" { + t.Errorf("Get() = %q, want %q", val, "hello") + } +} + +func TestNullableJSONMarshal(t *testing.T) { + // Test marshaling each state + tests := []struct { + name string + nullable Nullable[string] + want string + }{ + {"with value", NewNullableWithValue("test"), `"test"`}, + {"explicitly null", NewNullNullable[string](), "null"}, + {"unspecified", Nullable[string](nil), "null"}, // unspecified marshals as null + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := json.Marshal(tt.nullable) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + if string(data) != tt.want { + t.Errorf("Marshal() = %s, want %s", string(data), tt.want) + } + }) + } +} + +func TestNullableJSONUnmarshal(t *testing.T) { + tests := []struct { + name string + json string + wantNull bool + wantValue string + wantErr error + }{ + {"with value", `"test"`, false, "test", nil}, + {"explicitly null", "null", true, "", ErrNullableIsNull}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var n Nullable[string] + if err := json.Unmarshal([]byte(tt.json), &n); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + if n.IsNull() != tt.wantNull { + t.Errorf("IsNull() = %v, want %v", n.IsNull(), tt.wantNull) + } + val, err := n.Get() + if err != tt.wantErr { + t.Errorf("Get() error = %v, want %v", err, tt.wantErr) + } + if err == nil && val != tt.wantValue { + t.Errorf("Get() = %q, want %q", val, tt.wantValue) + } + }) + } +} + +// TestNullablePrimitiveTypeAlias verifies that nullable primitive schemas +// generate proper type aliases. +func TestNullablePrimitiveTypeAlias(t *testing.T) { + // SimpleRequiredNullable should be a type alias to Nullable[int] + var simple SimpleRequiredNullable + simple.Set(42) + + val, err := simple.Get() + if err != nil { + t.Fatalf("Get() failed: %v", err) + } + if val != 42 { + t.Errorf("Get() = %d, want 42", val) + } + + // Test null state + simple.SetNull() + if !simple.IsNull() { + t.Error("should be null after SetNull()") + } + + // Test unspecified state + simple.SetUnspecified() + if simple.IsSpecified() { + t.Error("should not be specified after SetUnspecified()") + } +} + +// TestAdditionalPropertiesFalse verifies that additionalProperties: false +// generates proper marshal/unmarshal that rejects extra fields. +func TestAdditionalPropertiesFalse(t *testing.T) { + // The struct has AdditionalProperties field but additionalProperties: false + // means unknown fields are still collected but not expected + req := PatchRequest{ + SimpleRequiredNullable: NewNullableWithValue(1), + ComplexRequiredNullable: NewNullNullable[ComplexRequiredNullable](), + AdditionalProperties: map[string]any{"extra": "value"}, + } + + // Should marshal with additional properties + data, err := json.Marshal(req) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + t.Logf("Marshaled: %s", string(data)) +} diff --git a/experimental/internal/codegen/test/issues/issue_1039/spec.yaml b/experimental/internal/codegen/test/issues/issue_1039/spec.yaml new file mode 100644 index 0000000000..8d827acef5 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1039/spec.yaml @@ -0,0 +1,86 @@ +# Issue 1039: Nullable types generation +# https://github.com/oapi-codegen/oapi-codegen/issues/1039 +# +# Make sure that nullable types are generated properly +openapi: 3.0.1 +info: + version: '0.0.1' + title: example + description: | + Make sure that nullable types are generated properly +paths: + /example: + patch: + operationId: examplePatch + requestBody: + description: The patch body + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PatchRequest" + responses: + '200': + description: "OK" + +components: + schemas: + PatchRequest: + type: object + description: A request to patch an existing user object. + required: + - simple_required_nullable + - complex_required_nullable + properties: + simple_required_nullable: + # required and nullable + $ref: "#/components/schemas/simple_required_nullable" + simple_optional_nullable: + # optional and nullable + $ref: "#/components/schemas/simple_optional_nullable" + simple_optional_non_nullable: + # optional and non-nullable + $ref: "#/components/schemas/simple_optional_non_nullable" + complex_required_nullable: + # required and nullable + $ref: "#/components/schemas/complex_required_nullable" + complex_optional_nullable: + # optional and nullable + $ref: "#/components/schemas/complex_optional_nullable" + additionalProperties: false + + simple_required_nullable: + type: integer + nullable: true + description: Simple required and nullable + + simple_optional_nullable: + type: integer + nullable: true + description: Simple optional and nullable + + simple_optional_non_nullable: + type: string + description: Simple optional and non nullable + + complex_required_nullable: + type: object + nullable: true + description: Complex required and nullable + properties: + name: + description: Optional and non nullable + type: string + + complex_optional_nullable: + type: object + description: Complex, optional and nullable + properties: + alias_name: + description: Optional and nullable + type: string + nullable: true + name: + description: Optional and non nullable + type: string + nullable: true diff --git a/experimental/internal/codegen/test/issues/issue_1397/doc.go b/experimental/internal/codegen/test/issues/issue_1397/doc.go new file mode 100644 index 0000000000..94fef2bfb0 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1397/doc.go @@ -0,0 +1,5 @@ +// Package issue_1397 tests basic type generation with x-go-type-name. +// https://github.com/oapi-codegen/oapi-codegen/issues/1397 +package issue_1397 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go new file mode 100644 index 0000000000..7fd6bbf827 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go @@ -0,0 +1,114 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Test +type MyTestRequest struct { + Field1 []TestField1Item `json:"field1,omitempty" form:"field1,omitempty"` // A array of enum values + Field2 *MyTestRequestNestedField `json:"field2,omitempty" form:"field2,omitempty"` // A nested object with allocated name + Field3 *TestField3 `json:"field3,omitempty" form:"field3,omitempty"` // A nested object without allocated name +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *MyTestRequest) ApplyDefaults() { + if s.Field2 != nil { + s.Field2.ApplyDefaults() + } + if s.Field3 != nil { + s.Field3.ApplyDefaults() + } +} + +// #/components/schemas/Test/properties/field1 +// A array of enum values +type TestField1 = []TestField1Item + +// #/components/schemas/Test/properties/field1/items +type TestField1Item string + +const ( + TestField1Item_option1 TestField1Item = "option1" + TestField1Item_option2 TestField1Item = "option2" +) + +// #/components/schemas/Test/properties/field2 +// A nested object with allocated name +type MyTestRequestNestedField struct { + Field1 bool `json:"field1" form:"field1"` + Field2 string `json:"field2" form:"field2"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *MyTestRequestNestedField) ApplyDefaults() { +} + +// #/components/schemas/Test/properties/field3 +// A nested object without allocated name +type TestField3 struct { + Field1 bool `json:"field1" form:"field1"` + Field2 string `json:"field2" form:"field2"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestField3) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/9xUzZKbMAy+8xSapFdCIO106lv30Jkc2kOnL+AYBbwDltcS283bd2zYAJt0Z3otJ/xZ", + "P58+WdrCkXlAKA9fPit40GwNyMUjNOgwaLHk4LeVFl7yhvJ4kzvdY7aFVsSzKorGSjucdob6grS3uaEa", + "G3Trg41JuIhZMvLotLcKNofdflduMuvOpDIAsdKhWhCCX8iSATxjYEtOQbnb7/aZod6TQyccvdi02Ov0", + "C8lh/INUhgI6PaKRCfKBPAaxyK9GAGeLXV3OZ4Aa2QTrJaX8CjoEfQE6A7qhh2fdDcgLayvY89IdkuEa", + "yYFSvPIuWq3QkTdLsK5ZXPT65ZhSwaclat2E7rO3IRLxdZ3VO3U6ZMF6Emxsuu46Mjqiqemz6z0h74s5", + "0zkRdajdrX113/5GgYBPgw1YL83zKeUtVN3osXoK8Vu/aQXfL/H9/MSnAVl+JDm+xVBrDQ//pCEN8j/L", + "+K6EmdfSptIKuQ5mg9cJjcWnFXOsFcg4668MkeWB6stM0pATdLJkrb3vrEkRikcmtxZgXAxvRfkQ8Kxg", + "sy3mLVJMK6SI1DdXDuzJ8bIz1f7jX1vfENXZnwAAAP//PTfE300FAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go new file mode 100644 index 0000000000..05ae316ffb --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go @@ -0,0 +1,81 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestNestedObjectTypes verifies that nested objects get proper types. +// https://github.com/oapi-codegen/oapi-codegen/issues/1397 +// +// Note: The x-go-type-name extension is not currently supported. Types are +// named based on their path in the schema rather than the specified names. +func TestNestedObjectTypes(t *testing.T) { + // Test schema should have array of enums, and two nested objects + test := MyTestRequest{ + Field1: []TestField1Item{ + TestField1Item_option1, + TestField1Item_option2, + }, + Field2: &MyTestRequestNestedField{ + Field1: true, + Field2: "value2", + }, + Field3: &TestField3{ + Field1: false, + Field2: "value3", + }, + } + + if len(test.Field1) != 2 { + t.Errorf("Field1 length = %d, want 2", len(test.Field1)) + } + if test.Field2.Field1 != true { + t.Errorf("Field2.Field1 = %v, want true", test.Field2.Field1) + } + if test.Field3.Field2 != "value3" { + t.Errorf("Field3.Field2 = %q, want %q", test.Field3.Field2, "value3") + } +} + +func TestEnumArrayField(t *testing.T) { + // Field1 is an array of enum values + _ = TestField1Item_option1 + _ = TestField1Item_option2 + + items := []TestField1Item{ + TestField1Item("option1"), + TestField1Item("option2"), + } + + if len(items) != 2 { + t.Errorf("items length = %d, want 2", len(items)) + } +} + +func TestTestJSONRoundTrip(t *testing.T) { + original := MyTestRequest{ + Field1: []TestField1Item{TestField1Item_option1}, + Field2: &MyTestRequestNestedField{Field1: true, Field2: "test"}, + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded MyTestRequest + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if len(decoded.Field1) != 1 { + t.Errorf("Field1 length = %d, want 1", len(decoded.Field1)) + } + if decoded.Field2 == nil { + t.Fatal("Field2 should not be nil") + } + if decoded.Field2.Field1 != true { + t.Errorf("Field2.Field1 = %v, want true", decoded.Field2.Field1) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_1397/spec.yaml b/experimental/internal/codegen/test/issues/issue_1397/spec.yaml new file mode 100644 index 0000000000..3f1289ceac --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1397/spec.yaml @@ -0,0 +1,57 @@ +# Issue 1397: Basic type generation with x-go-type-name +# https://github.com/oapi-codegen/oapi-codegen/issues/1397 +openapi: "3.0.1" +info: + title: Issue 1397 Test + version: 1.0.0 +components: + schemas: + Test: + type: object + properties: + field1: + description: A array of enum values + items: + enum: + - option1 + - option2 + type: string + maxItems: 5 + minItems: 0 + type: array + field2: + description: A nested object with allocated name + properties: + field1: + type: boolean + field2: + type: string + required: + - field1 + - field2 + type: object + x-go-type-name: MyTestRequestNestedField + field3: + description: A nested object without allocated name + properties: + field1: + type: boolean + field2: + type: string + required: + - field1 + - field2 + type: object + x-go-type-name: MyTestRequest +paths: + /test: + get: + operationId: test + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Test" + responses: + 204: + description: good diff --git a/experimental/internal/codegen/test/issues/issue_1429/doc.go b/experimental/internal/codegen/test/issues/issue_1429/doc.go new file mode 100644 index 0000000000..ab6cbd6e21 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1429/doc.go @@ -0,0 +1,5 @@ +// Package issue_1429 tests that enums inside anyOf members are generated. +// https://github.com/oapi-codegen/oapi-codegen/issues/1429 +package issue_1429 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go new file mode 100644 index 0000000000..993992b0d7 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go @@ -0,0 +1,149 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/test +type Test struct { + TestAnyOf0 *TestAnyOf0 + TestAnyOf1 *TestAnyOf1 +} + +func (u Test) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.TestAnyOf0 != nil { + data, err := json.Marshal(u.TestAnyOf0) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.TestAnyOf1 != nil { + data, err := json.Marshal(u.TestAnyOf1) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *Test) UnmarshalJSON(data []byte) error { + var v0 TestAnyOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.TestAnyOf0 = &v0 + } + + var v1 TestAnyOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.TestAnyOf1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *Test) ApplyDefaults() { + if u.TestAnyOf0 != nil { + u.TestAnyOf0.ApplyDefaults() + } + if u.TestAnyOf1 != nil { + u.TestAnyOf1.ApplyDefaults() + } +} + +// #/components/schemas/test/anyOf/0 +type TestAnyOf0 struct { + FieldA *string `json:"fieldA,omitempty" form:"fieldA,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestAnyOf0) ApplyDefaults() { +} + +// #/components/schemas/test/anyOf/1 +type TestAnyOf1 struct { + FieldA *string `json:"fieldA,omitempty" form:"fieldA,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestAnyOf1) ApplyDefaults() { +} + +// #/components/schemas/test/anyOf/1/properties/fieldA +type TestAnyOf1FieldA string + +const ( + TestAnyOf1FieldA_foo TestAnyOf1FieldA = "foo" + TestAnyOf1FieldA_bar TestAnyOf1FieldA = "bar" +) + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/6xSsW7cMAzd9RUPcYEsvfMl7VJtHTN1KdBZtmlLwZkURLrF/X0hOwdfrh3DiXqkHt8T", + "1eBFdSE8fX3+5kG8zGAxTMRUgtGAP5EYi9YsWUTgy4/RNYhmWX3bTsni0h17mVsJOR16GWgifn9IdYS2", + "dYZrXINflTMgF8lU7ILEmgZC4I0eM80dFcSgFauiPsMibfLsksk10CjLeUBHu9ajk0wccvL4cjwdTy7x", + "KN4BluxM/sYpfpKaA35T0STs8bT252BR64XWSK0mwERvCVDVBkvCL4O/MtQopFlYSa+NwMPz6fSwH4Fe", + "2IjtFgJCzufUr5Ttqwq/rwLaR5rDPQp8KjR6PDZtL3MWJjZtt15dlT+6vVBvv9U2ot0a1rf0kO6V+quZ", + "dQP7yMN1S+nWXo0x0Xn4fi9uY1QriaePJdmifoF/H+SAUeQ/aBeK+xsAAP//dJpKJ+ICAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go new file mode 100644 index 0000000000..9020a645b2 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go @@ -0,0 +1,37 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestEnumGenerated verifies that the enum type is generated for properties inside anyOf. +// Issue 1429: enum type was not being generated when used inside anyOf. +func TestEnumGenerated(t *testing.T) { + // The enum type should exist and have the expected constants + _ = TestAnyOf1FieldA_foo + _ = TestAnyOf1FieldA_bar + + // The alias should also exist + _ = TestAnyOf1FieldA(TestAnyOf1FieldA_foo) +} + +// TestAnyOfMarshal verifies that the anyOf type can be marshaled. +func TestAnyOfMarshal(t *testing.T) { + test := Test{ + TestAnyOf1: &TestAnyOf1{ + FieldA: ptr("foo"), + }, + } + + data, err := json.Marshal(test) + if err != nil { + t.Fatalf("Failed to marshal: %v", err) + } + + t.Logf("Marshaled: %s", string(data)) +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/experimental/internal/codegen/test/issues/issue_1429/spec.yaml b/experimental/internal/codegen/test/issues/issue_1429/spec.yaml new file mode 100644 index 0000000000..a07aef195a --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1429/spec.yaml @@ -0,0 +1,33 @@ +# Issue 1429: enum not generated when used with anyOf +# https://github.com/oapi-codegen/oapi-codegen/issues/1429 +# +# When a property inside an anyOf member has an enum, the enum type +# should be generated. +openapi: 3.0.0 +info: + title: Issue 1429 Test + version: 1.0.0 +paths: + /test: + get: + operationId: Test + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/test' +components: + schemas: + test: + type: object + anyOf: + - properties: + fieldA: + type: string + - properties: + fieldA: + type: string + enum: + - foo + - bar diff --git a/experimental/internal/codegen/test/issues/issue_1496/doc.go b/experimental/internal/codegen/test/issues/issue_1496/doc.go new file mode 100644 index 0000000000..e09cb2f78e --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1496/doc.go @@ -0,0 +1,5 @@ +// Package issue_1496 tests that inline schemas generate valid Go identifiers. +// https://github.com/oapi-codegen/oapi-codegen/issues/1496 +package issue_1496 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go new file mode 100644 index 0000000000..2f95e2dbf8 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go @@ -0,0 +1,168 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" +) + +// #/paths//something/get/responses/200/content/application/json/schema +type GetSomethingJSONResponse struct { + Results []GetSomething200ResponseJSON2 `json:"results" form:"results"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *GetSomethingJSONResponse) ApplyDefaults() { +} + +// #/paths//something/get/responses/200/content/application/json/schema/properties/results +type GetSomething200ResponseJSON1 = []GetSomething200ResponseJSON2 + +// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items +type GetSomething200ResponseJSON2 struct { + GetSomething200ResponseJSONAnyOf0 *GetSomething200ResponseJSONAnyOf0 + GetSomething200ResponseJSONAnyOf11 *GetSomething200ResponseJSONAnyOf11 +} + +func (u GetSomething200ResponseJSON2) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.GetSomething200ResponseJSONAnyOf0 != nil { + data, err := json.Marshal(u.GetSomething200ResponseJSONAnyOf0) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + if u.GetSomething200ResponseJSONAnyOf11 != nil { + data, err := json.Marshal(u.GetSomething200ResponseJSONAnyOf11) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *GetSomething200ResponseJSON2) UnmarshalJSON(data []byte) error { + var v0 GetSomething200ResponseJSONAnyOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.GetSomething200ResponseJSONAnyOf0 = &v0 + } + + var v1 GetSomething200ResponseJSONAnyOf11 + if err := json.Unmarshal(data, &v1); err == nil { + u.GetSomething200ResponseJSONAnyOf11 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *GetSomething200ResponseJSON2) ApplyDefaults() { + if u.GetSomething200ResponseJSONAnyOf0 != nil { + u.GetSomething200ResponseJSONAnyOf0.ApplyDefaults() + } + if u.GetSomething200ResponseJSONAnyOf11 != nil { + u.GetSomething200ResponseJSONAnyOf11.ApplyDefaults() + } +} + +// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/0 +type GetSomething200ResponseJSONAnyOf0 struct { + Order *string `json:"order,omitempty" form:"order,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *GetSomething200ResponseJSONAnyOf0) ApplyDefaults() { +} + +// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/1 +type GetSomething200ResponseJSONAnyOf11 struct { + Error *GetSomething200ResponseJSONAnyOf12 `json:"error,omitempty" form:"error,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *GetSomething200ResponseJSONAnyOf11) ApplyDefaults() { + if s.Error != nil { + s.Error.ApplyDefaults() + } +} + +// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/1/properties/error +type GetSomething200ResponseJSONAnyOf12 struct { + Code *float32 `json:"code,omitempty" form:"code,omitempty"` + Message *string `json:"message,omitempty" form:"message,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *GetSomething200ResponseJSONAnyOf12) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/7xTTW+bQBC98yue4ksrJeC0VaVy66nyKVJTqcdoDWOYyMxud4ZY/vfVgqlJncTJJZyY", + "fTP7PhgWWKn2hOsv376W+C5e9p3vFX59T5VBq5Y6hx1bCy90s0FDQtEZKVge3JZrcE1ivGGK2QKtWdCy", + "KBq2tl/nle8K7wJfVb6mhuRxwYlai8SdLbIFfrckcAKWLQtN5CxwiKTBixJ6JYWT/c2mGARdwlr6p6qG", + "7QNBXEfZAjunUHPRWJrRg4P03ZoiPlDe5Jf4tFze/STtt6Z3K6PuI3YtVy14Zk/ww+eZDyQucInP+TJf", + "ZiwbX2aAsW2pnIWIX6SWAQ8Ulb2UuB76g7NW00ChviNrWZpUAQ3Z+AL4kDywl1VdpvPbqfOATxnoNICk", + "/1gANWkVOdhAfHHbVxWpXswaKi9GYvMZwIWw5WpgLu7Vy2MUh+/w/ymGqMvDppyAkf70HKk+HQOukpWU", + "+QkWYgrBeO5xfucw9RQ0qXExuv2TOBt1z4xiXKjnwCT4Ra+v1X98fKwpvtwyOVKLxxV4B2kUo3+ltLOc", + "b+Ed17Om810T/fgrn23vSNU1b7j3kPjfAAAA///mDrwBGwUAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go new file mode 100644 index 0000000000..5056b4583e --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go @@ -0,0 +1,41 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestValidIdentifiers verifies that all generated type names are valid Go identifiers. +// Issue 1496: Inline schemas in responses were generating identifiers starting with numbers. +func TestValidIdentifiers(t *testing.T) { + // If this compiles, the identifiers are valid + response := GetSomethingJSONResponse{ + Results: []GetSomething200ResponseJSON2{ + { + GetSomething200ResponseJSONAnyOf0: &GetSomething200ResponseJSONAnyOf0{ + Order: ptr("order-123"), + }, + }, + { + GetSomething200ResponseJSONAnyOf11: &GetSomething200ResponseJSONAnyOf11{ + Error: &GetSomething200ResponseJSONAnyOf12{ + Code: ptr(float32(400)), + Message: ptr("Bad request"), + }, + }, + }, + }, + } + + // Should be able to marshal + data, err := json.Marshal(response) + if err != nil { + t.Fatalf("Failed to marshal response: %v", err) + } + + t.Logf("Marshaled response: %s", string(data)) +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/experimental/internal/codegen/test/issues/issue_1496/spec.yaml b/experimental/internal/codegen/test/issues/issue_1496/spec.yaml new file mode 100644 index 0000000000..f4156e97ad --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1496/spec.yaml @@ -0,0 +1,40 @@ +# Issue 1496: Anonymous object schema with oneOf generates invalid identifier +# https://github.com/oapi-codegen/oapi-codegen/issues/1496 +# +# When an inline schema in a response uses anyOf/oneOf, the generated type name +# was starting with a number (e.g., 200_Results_Item) which is invalid in Go. +openapi: 3.0.0 +info: + title: Issue 1496 Test + version: 1.0.0 +paths: + /something: + get: + operationId: getSomething + responses: + 200: + description: "Success" + content: + application/json: + schema: + type: object + required: + - results + properties: + results: + type: array + items: + anyOf: + - type: object + properties: + order: + type: string + - type: object + properties: + error: + type: object + properties: + code: + type: number + message: + type: string diff --git a/experimental/internal/codegen/test/issues/issue_1710/doc.go b/experimental/internal/codegen/test/issues/issue_1710/doc.go new file mode 100644 index 0000000000..3ce6436c35 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1710/doc.go @@ -0,0 +1,5 @@ +// Package issue_1710 tests that fields are not lost in nested allOf oneOf structures. +// https://github.com/oapi-codegen/oapi-codegen/issues/1710 +package issue_1710 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go new file mode 100644 index 0000000000..6efb31f3a5 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go @@ -0,0 +1,212 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/BasePrompt +type BasePrompt struct { + Name string `json:"name" form:"name"` + Version int `json:"version" form:"version"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *BasePrompt) ApplyDefaults() { +} + +// #/components/schemas/TextPrompt +type TextPrompt struct { + Prompt string `json:"prompt" form:"prompt"` + Name string `json:"name" form:"name"` + Version int `json:"version" form:"version"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TextPrompt) ApplyDefaults() { +} + +// #/components/schemas/ChatMessage +type ChatMessage struct { + Role string `json:"role" form:"role"` + Content string `json:"content" form:"content"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ChatMessage) ApplyDefaults() { +} + +// #/components/schemas/ChatPrompt +type ChatPrompt struct { + Prompt []ChatMessage `json:"prompt" form:"prompt"` + Name string `json:"name" form:"name"` + Version int `json:"version" form:"version"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ChatPrompt) ApplyDefaults() { +} + +// #/components/schemas/ChatPrompt/properties/prompt +type ChatPromptPrompt = []ChatMessage + +// #/components/schemas/Prompt +type Prompt struct { + PromptOneOf0 *PromptOneOf0 + PromptOneOf1 *PromptOneOf1 +} + +func (u Prompt) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.PromptOneOf0 != nil { + count++ + data, err = json.Marshal(u.PromptOneOf0) + if err != nil { + return nil, err + } + } + if u.PromptOneOf1 != nil { + count++ + data, err = json.Marshal(u.PromptOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("Prompt: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *Prompt) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 PromptOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.PromptOneOf0 = &v0 + successCount++ + } + + var v1 PromptOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.PromptOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("Prompt: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *Prompt) ApplyDefaults() { + if u.PromptOneOf0 != nil { + u.PromptOneOf0.ApplyDefaults() + } + if u.PromptOneOf1 != nil { + u.PromptOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/Prompt/oneOf/0 +type PromptOneOf0 struct { + Type *string `json:"type,omitempty" form:"type,omitempty"` + Prompt []ChatMessage `json:"prompt" form:"prompt"` + Name string `json:"name" form:"name"` + Version int `json:"version" form:"version"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *PromptOneOf0) ApplyDefaults() { +} + +// #/components/schemas/Prompt/oneOf/0/allOf/0/properties/type +type PromptOneOf0AllOf0Type string + +const ( + PromptOneOf0AllOf0Type_chat PromptOneOf0AllOf0Type = "chat" +) + +// #/components/schemas/Prompt/oneOf/1 +type PromptOneOf1 struct { + Type *string `json:"type,omitempty" form:"type,omitempty"` + Prompt string `json:"prompt" form:"prompt"` + Name string `json:"name" form:"name"` + Version int `json:"version" form:"version"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *PromptOneOf1) ApplyDefaults() { +} + +// #/components/schemas/Prompt/oneOf/1/allOf/0/properties/type +type PromptOneOf1AllOf0Type string + +const ( + PromptOneOf1AllOf0Type_text PromptOneOf1AllOf0Type = "text" +) + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/9SUT4/TMBDF7/kUIwWpFzZpxQEpRzhxQMuhEmc3eYmNEtt4JvtHiO+O4qYbh2132RVC", + "oqfO68zzm5+b5PSJeQTt3u+2FbUGfUO9YyFjyYIFDam+v27JWVy3WU5axHNVlp0RPR6K2g2lU95c1a5B", + "B7suzOTN5WSe5VlOXzUsjWxstza/NaKPJ7ydlGMOJtZu7Bs6gHwAI9ygKbKc9hq08cENXjZz5FvFdMDk", + "O4UvMudhlTcVvSu2xTYztnVVRiRGelTJyrQHS0Z0g8DG2Yp2sd8r0VzRj59Z7QbvLKzwNM+1xqDiV6IP", + "ivElpjjWRHLvUZE7fEMts+SD8whiwKcmIqsGLNVpjCUY2z3Ip0SP+owVdAizHvB9NAHN0ncV/ZNydorK", + "Hnfyqsx+NXQh9bkwx8FZiLed/vomoK1ok5cL53KGXC58N3Hio1byGcyqwwvDB9c/D7x2VmBfs+Jkn5Sz", + "0UPmv8pbhaDuE9UIBk7b6EmmCcPNP7m09fLxEU+tztA4c+STvZcIrrg9Ui/8CZYP7DicG4s3rJX8Fu45", + "6CmTS9yXNf97QoK7lxBaXkt/TOhXAAAA//+WRkFKuQYAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go new file mode 100644 index 0000000000..345ab353e9 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go @@ -0,0 +1,102 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestPromptOneOfHasPromptField verifies that the 'prompt' field is not lost +// in nested allOf/oneOf structures. +// https://github.com/oapi-codegen/oapi-codegen/issues/1710 +func TestPromptOneOfHasPromptField(t *testing.T) { + // Test ChatPrompt variant (PromptOneOf0) - prompt is []ChatMessage + chatType := "chat" + chatPrompt := PromptOneOf0{ + Type: &chatType, + Prompt: []ChatMessage{ + {Role: "user", Content: "hello"}, + }, + } + + if chatPrompt.Type == nil || *chatPrompt.Type != "chat" { + t.Error("ChatPrompt variant should have Type='chat'") + } + if len(chatPrompt.Prompt) != 1 { + t.Errorf("ChatPrompt.Prompt should have 1 message, got %d", len(chatPrompt.Prompt)) + } + if chatPrompt.Prompt[0].Role != "user" { + t.Errorf("ChatPrompt.Prompt[0].Role = %q, want %q", chatPrompt.Prompt[0].Role, "user") + } + + // Test TextPrompt variant (PromptOneOf1) - prompt is string + textType := "text" + textPrompt := PromptOneOf1{ + Type: &textType, + Prompt: "Hello, world!", + } + + if textPrompt.Type == nil || *textPrompt.Type != "text" { + t.Error("TextPrompt variant should have Type='text'") + } + if textPrompt.Prompt != "Hello, world!" { + t.Errorf("TextPrompt.Prompt = %q, want %q", textPrompt.Prompt, "Hello, world!") + } +} + +func TestPromptJSONRoundTrip(t *testing.T) { + // Test chat prompt variant + chatType := "chat" + chatVariant := Prompt{ + PromptOneOf0: &PromptOneOf0{ + Type: &chatType, + Prompt: []ChatMessage{ + {Role: "user", Content: "test message"}, + }, + }, + } + + data, err := json.Marshal(chatVariant) + if err != nil { + t.Fatalf("Marshal chat variant failed: %v", err) + } + + var decoded Prompt + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal chat variant failed: %v", err) + } + + if decoded.PromptOneOf0 == nil { + t.Fatal("Expected PromptOneOf0 to be set after unmarshal") + } + if len(decoded.PromptOneOf0.Prompt) != 1 { + t.Errorf("Expected 1 message, got %d", len(decoded.PromptOneOf0.Prompt)) + } +} + +func TestTextPromptHasPromptField(t *testing.T) { + // Verify TextPrompt (from allOf) has the prompt field + tp := TextPrompt{ + Prompt: "my prompt", + Name: "test", + Version: 1, + } + + if tp.Prompt != "my prompt" { + t.Errorf("TextPrompt.Prompt = %q, want %q", tp.Prompt, "my prompt") + } +} + +func TestChatPromptHasPromptField(t *testing.T) { + // Verify ChatPrompt (from allOf) has the prompt field + cp := ChatPrompt{ + Prompt: []ChatMessage{ + {Role: "assistant", Content: "hello"}, + }, + Name: "test", + Version: 1, + } + + if len(cp.Prompt) != 1 { + t.Errorf("ChatPrompt.Prompt should have 1 message, got %d", len(cp.Prompt)) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_1710/spec.yaml b/experimental/internal/codegen/test/issues/issue_1710/spec.yaml new file mode 100644 index 0000000000..b1219e00d7 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_1710/spec.yaml @@ -0,0 +1,76 @@ +# Issue 1710: field lost in nested allOf oneOf +# https://github.com/oapi-codegen/oapi-codegen/issues/1710 +# +# When using nested allOf with oneOf, all fields should be preserved. +# The 'prompt' field was being lost. +openapi: 3.0.0 +info: + title: Issue 1710 Test + version: 1.0.0 +paths: {} +components: + schemas: + BasePrompt: + type: object + properties: + name: + type: string + version: + type: integer + required: + - name + - version + TextPrompt: + type: object + properties: + prompt: + type: string + required: + - prompt + allOf: + - $ref: '#/components/schemas/BasePrompt' + ChatMessage: + type: object + properties: + role: + type: string + content: + type: string + required: + - role + - content + ChatPrompt: + type: object + properties: + prompt: + type: array + items: + $ref: '#/components/schemas/ChatMessage' + required: + - prompt + allOf: + - $ref: '#/components/schemas/BasePrompt' + Prompt: + oneOf: + - type: object + allOf: + - type: object + properties: + type: + type: string + enum: + - chat + - $ref: '#/components/schemas/ChatPrompt' + required: + - type + - type: object + allOf: + - type: object + properties: + type: + type: string + enum: + - text + - $ref: '#/components/schemas/TextPrompt' + required: + - type diff --git a/experimental/internal/codegen/test/issues/issue_193/doc.go b/experimental/internal/codegen/test/issues/issue_193/doc.go new file mode 100644 index 0000000000..dcf3fbff8c --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_193/doc.go @@ -0,0 +1,5 @@ +// Package issue_193 tests allOf with additionalProperties merging. +// https://github.com/oapi-codegen/oapi-codegen/issues/193 +package issue_193 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go new file mode 100644 index 0000000000..33a950f497 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go @@ -0,0 +1,71 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Person +type Person struct { + Metadata string `json:"metadata" form:"metadata"` + Name *string `json:"name,omitempty" form:"name,omitempty"` + Age *float32 `json:"age,omitempty" form:"age,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Person) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/6yQvW7jQAyE+32KAVzbsuHK21151fkV1itK4kG73FtSFwRB3j2QHP8BMZAiHTn4SM5w", + "hd+qE2F32Hv8Gsc/HV7YBoS2ZWPJYTxWKVSNSZGo9px7t8JgVtQ3Tc82TKdNlNRIKLyO0lJP+bHh+YI2", + "u8PeSaEcCnvsN9vN1nHuxDvA2EbyMFKDxoFScMB/qsqSPXYLW4IN6vH27qKkIpmy6Tx75pcSOFJVyeca", + "CHOeSwOsECUlyeiYxlav+hr2WshDTn8p2lXGl0/wsDrRHVTp38SVWn+nzTsTWWiDhTu53LY8wBf0UcWn", + "LbU6P/2WoiwhoYUidxx/Ns4zjzkk+pa/5VL/hM1TOlF1HwEAAP//7z/Hg3YCAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types_test.go b/experimental/internal/codegen/test/issues/issue_193/output/types_test.go new file mode 100644 index 0000000000..301c97d923 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_193/output/types_test.go @@ -0,0 +1,76 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestAllOfWithAdditionalProperties verifies that allOf with additionalProperties: true +// merges fields correctly from multiple allOf members. +// https://github.com/oapi-codegen/oapi-codegen/issues/193 +func TestAllOfWithAdditionalProperties(t *testing.T) { + name := "John" + age := float32(30) + + person := Person{ + Metadata: "some-metadata", + Name: &name, + Age: &age, + } + + // All fields from both allOf members should be present + if person.Metadata != "some-metadata" { + t.Errorf("Metadata = %q, want %q", person.Metadata, "some-metadata") + } + if *person.Name != "John" { + t.Errorf("Name = %q, want %q", *person.Name, "John") + } + if *person.Age != 30 { + t.Errorf("Age = %v, want %v", *person.Age, 30) + } +} + +func TestPersonJSONRoundTrip(t *testing.T) { + name := "Jane" + age := float32(25) + original := Person{ + Metadata: "meta", + Name: &name, + Age: &age, + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded Person + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if decoded.Metadata != original.Metadata { + t.Errorf("Metadata mismatch: got %q, want %q", decoded.Metadata, original.Metadata) + } + if *decoded.Name != *original.Name { + t.Errorf("Name mismatch: got %q, want %q", *decoded.Name, *original.Name) + } + if *decoded.Age != *original.Age { + t.Errorf("Age mismatch: got %v, want %v", *decoded.Age, *original.Age) + } +} + +func TestMetadataIsRequired(t *testing.T) { + // Metadata is required (no omitempty), so empty struct should marshal with empty string + person := Person{} + data, err := json.Marshal(person) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + // Should contain "metadata" even if empty + expected := `{"metadata":""}` + if string(data) != expected { + t.Errorf("Marshal result = %s, want %s", string(data), expected) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_193/spec.yaml b/experimental/internal/codegen/test/issues/issue_193/spec.yaml new file mode 100644 index 0000000000..375d227fb4 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_193/spec.yaml @@ -0,0 +1,27 @@ +# Issue 193: AllOf with additionalProperties merging +# https://github.com/oapi-codegen/oapi-codegen/issues/193 +openapi: 3.0.0 +info: + title: test schema + version: 1.0.0 +paths: {} +components: + schemas: + Person: + allOf: + # common fields + - type: object + additionalProperties: true + required: + - metadata + properties: + metadata: + type: string + # person specific fields + - type: object + additionalProperties: true + properties: + name: + type: string + age: + type: number diff --git a/experimental/internal/codegen/test/issues/issue_2102/doc.go b/experimental/internal/codegen/test/issues/issue_2102/doc.go new file mode 100644 index 0000000000..753b091ce1 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_2102/doc.go @@ -0,0 +1,5 @@ +// Package issue_2102 tests that properties defined at the same level as allOf are included. +// https://github.com/oapi-codegen/oapi-codegen/issues/2102 +package issue_2102 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go new file mode 100644 index 0000000000..43d8ca049e --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go @@ -0,0 +1,82 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Foo +type Foo struct { + Foo string `json:"foo" form:"foo"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Foo) ApplyDefaults() { +} + +// #/components/schemas/Bar +type Bar struct { + Bar string `json:"bar" form:"bar"` + Foo string `json:"foo" form:"foo"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Bar) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/3xSwY6bMBC98xVPS6VcmpBNbxz3sFJPvVTqNQYP2CvwuJ5hq/x9BSQ16UbLBfzmzXsz", + "z5T4LjIRTs/HUw0zDD86/PHqEBNHSupJYBRiRsJA7zRgf1dKBN8HTmSLEk41Sl1VvVc3NYeWx4pN9PuW", + "LfUU7g9+9pVqNi7KosQvRwEG0joaDZwRNKwO5+x2hgkW52XI8zyVOtpM9rUoF2QznqXOB7KwPlGrwwUc", + "1qbVRBxPg0VDGCn1ZJfNP6p0iccFW+NJ1FGi0JIcCo4UTPQ1vh2Oh2PhQ8d1AajXgepNtPhJogXwTkk8", + "hxrPCz8adTI3VI1J8xvoSdcPQKZxNOlSozHpCiWSyEFIbhzg6XQ8PuUjYEna5KMuPrl1floOSkG3bMDE", + "OPjWzPzqTTjcV3EN638U+JKoq7Erq5bHyIGCSrVypXoxaVdkfG6+lladV+aboF4i1eDmjVr9t+XvySey", + "2XOPjvl6yjeT613Wy5qiyYd+gV9u8T70e6TY5I6Hilj/hu2InwXyyrzbUD9uuOLzdf0NAAD//90rMTaT", + "AwAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go b/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go new file mode 100644 index 0000000000..b4916b2c33 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go @@ -0,0 +1,52 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestBarHasBothProperties verifies that Bar has both foo and bar properties. +// Issue 2102: When a schema has both properties and allOf at the same level, +// the properties were being ignored. +func TestBarHasBothProperties(t *testing.T) { + // Bar should have both foo (from allOf ref to Foo) and bar (from direct properties) + bar := Bar{ + Foo: "test-foo", + Bar: "test-bar", + } + + // Should be able to marshal/unmarshal + data, err := json.Marshal(bar) + if err != nil { + t.Fatalf("Failed to marshal Bar: %v", err) + } + + var unmarshaled Bar + if err := json.Unmarshal(data, &unmarshaled); err != nil { + t.Fatalf("Failed to unmarshal Bar: %v", err) + } + + if unmarshaled.Foo != "test-foo" { + t.Errorf("Expected Foo to be 'test-foo', got %q", unmarshaled.Foo) + } + if unmarshaled.Bar != "test-bar" { + t.Errorf("Expected Bar to be 'test-bar', got %q", unmarshaled.Bar) + } +} + +// TestBarRequiredFields verifies that bar is required (from allOf member's required array). +func TestBarRequiredFields(t *testing.T) { + // Both foo and bar should be required (no omitempty), so an empty struct + // should marshal with empty string values + bar := Bar{} + data, err := json.Marshal(bar) + if err != nil { + t.Fatalf("Failed to marshal empty Bar: %v", err) + } + + // Both fields should be present in JSON + expected := `{"bar":"","foo":""}` + if string(data) != expected { + t.Errorf("Expected %s, got %s", expected, string(data)) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_2102/spec.yaml b/experimental/internal/codegen/test/issues/issue_2102/spec.yaml new file mode 100644 index 0000000000..cbafb5a6d3 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_2102/spec.yaml @@ -0,0 +1,39 @@ +# Issue 2102: allOf with properties at same level - properties are ignored +# https://github.com/oapi-codegen/oapi-codegen/issues/2102 +# +# When a schema has both `properties` and `allOf` at the same level, +# the properties defined directly on the schema should be merged with +# the properties from the allOf references. +openapi: 3.0.0 +info: + title: Issue 2102 Test + version: 1.0.0 +paths: + /bar: + get: + summary: bar + responses: + "200": + description: bar + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + required: + - foo + properties: + foo: + type: string + Bar: + type: object + properties: + bar: + type: string + allOf: + - $ref: '#/components/schemas/Foo' + - required: + - bar diff --git a/experimental/internal/codegen/test/issues/issue_312/doc.go b/experimental/internal/codegen/test/issues/issue_312/doc.go new file mode 100644 index 0000000000..0f29af76ad --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_312/doc.go @@ -0,0 +1,6 @@ +// Package issue_312 tests proper escaping of paths with special characters. +// https://github.com/oapi-codegen/oapi-codegen/issues/312 +// This tests paths with colons like /pets:validate +package issue_312 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go new file mode 100644 index 0000000000..f5f81dbf6e --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go @@ -0,0 +1,97 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Pet +type Pet struct { + Name string `json:"name" form:"name"` // The name of the pet. +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Pet) ApplyDefaults() { +} + +// #/components/schemas/PetNames +type PetNames struct { + Names []string `json:"names" form:"names"` // The names of the pets. +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *PetNames) ApplyDefaults() { +} + +// #/components/schemas/Error +type Error struct { + Code int32 `json:"code" form:"code"` // Error code + Message string `json:"message" form:"message"` // Error message +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Error) ApplyDefaults() { +} + +// #/paths//pets:validate/post/responses/200/content/application/json/schema +type ValidatePetsJSONResponse = []Pet + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/8SVTW/bPAzH7/oURPMAOdVOk5uOzzAMvQw5DLurMm2rtSVNpLsFw777IDmu7TpxsQ3D", + "bjEpkb8/X5QN3BN1CIe7vYSj4hqQtPLGVmIDNbMnmeeV4bp7yLRrc6e8udWuwArt/MPEOJQf7vZiA+9q", + "1E8EPjiP4SUkuBK84prgq+EayKM2qgFdq6A0YyBozBOCdo2zJJxHq7yRcHPIdtnuRhhbOikAnjGQcVbC", + "XbQLADbcoByVACOxACiQdDCe0+E1pKBajPlFoos5co9M8lk1plCM0QLgHXH/C4C6tlXhJOHz+QjEC2fn", + "LO+lAxFBRfd9IWFIchz9Ab90SPy/K05Dwt5oAhYSOHT4YtbOMloezwEo7xujU4L8kZyd+gBI19iquQ3g", + "v4ClhO0m1671zqJlyvuTlB+RP6oWafuCR95ZQhqDbPe73XYac1aDJHFagCvgb6Ffgwfgk0cJKgR1WvgM", + "Y0vLK29q3opRTKm6hq/q6yx+86gZC8AQXPhbKteA38fE22F08+8e+b740ceocDm4H5BjR6Ayz2jBFGjZ", + "lAZDdmlGK+Qj8tkz7stIeAtWtSghZZ1wGyvTyk9MV+b4suq+r8Qhvkh/On3/oi1pjkZ7vHx29XGOY2t6", + "re7hETWLV7V6VeihE+kxYzOtReqDWK3gokKfakz34mvIdXqqMjHgpdX/DUZ6A5KWlK/39yIkTSgpE6t7", + "PhOfPGlN5Ap6/D+bfLZIpKq1gscLSynGMlY4fQlKF1rFyXPYXxOZ8OYMZ4Jf7WkfacD/GQAA//+iio0s", + "6AcAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types_test.go b/experimental/internal/codegen/test/issues/issue_312/output/types_test.go new file mode 100644 index 0000000000..3a2818f642 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_312/output/types_test.go @@ -0,0 +1,72 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestPathWithColon verifies that paths with colons (like /pets:validate) generate properly. +// https://github.com/oapi-codegen/oapi-codegen/issues/312 +func TestPathWithColonGeneratesTypes(t *testing.T) { + // The path /pets:validate should generate a ValidatePetsJSONResponse type + response := ValidatePetsJSONResponse{ + {Name: "Fluffy"}, + {Name: "Spot"}, + } + + if len(response) != 2 { + t.Errorf("response length = %d, want 2", len(response)) + } + if response[0].Name != "Fluffy" { + t.Errorf("response[0].Name = %q, want %q", response[0].Name, "Fluffy") + } +} + +func TestPetSchema(t *testing.T) { + pet := Pet{ + Name: "Max", + } + + data, err := json.Marshal(pet) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + expected := `{"name":"Max"}` + if string(data) != expected { + t.Errorf("Marshal result = %s, want %s", string(data), expected) + } +} + +func TestPetNamesSchema(t *testing.T) { + petNames := PetNames{ + Names: []string{"Fluffy", "Spot", "Max"}, + } + + data, err := json.Marshal(petNames) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded PetNames + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if len(decoded.Names) != 3 { + t.Errorf("Names length = %d, want 3", len(decoded.Names)) + } +} + +func TestErrorSchema(t *testing.T) { + err := Error{ + Code: 404, + Message: "Not Found", + } + + data, _ := json.Marshal(err) + expected := `{"code":404,"message":"Not Found"}` + if string(data) != expected { + t.Errorf("Marshal result = %s, want %s", string(data), expected) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_312/spec.yaml b/experimental/internal/codegen/test/issues/issue_312/spec.yaml new file mode 100644 index 0000000000..fa458ec41f --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_312/spec.yaml @@ -0,0 +1,86 @@ +# Issue 312: Path escaping +# https://github.com/oapi-codegen/oapi-codegen/issues/312 +# Checks proper escaping of paths with special characters like colons +openapi: "3.0.0" +info: + version: 1.0.0 + title: Issue 312 test + description: Checks proper escaping of parameters +paths: + /pets:validate: + post: + summary: Validate pets + description: Validate pets + operationId: validatePets + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PetNames' + responses: + '200': + description: valid pets + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /pets/{petId}: + get: + summary: Get pet given identifier. + operationId: getPet + parameters: + - name: petId + in: path + required: true + schema: + type: string + responses: + '200': + description: valid pet + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + type: object + required: + - name + properties: + name: + type: string + description: The name of the pet. + + PetNames: + type: object + required: + - names + properties: + names: + type: array + description: The names of the pets. + items: + type: string + + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + description: Error code + message: + type: string + description: Error message diff --git a/experimental/internal/codegen/test/issues/issue_502/doc.go b/experimental/internal/codegen/test/issues/issue_502/doc.go new file mode 100644 index 0000000000..992436f9e7 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_502/doc.go @@ -0,0 +1,5 @@ +// Package issue_502 tests that anyOf with only one ref generates the referenced type. +// https://github.com/oapi-codegen/oapi-codegen/issues/502 +package issue_502 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go new file mode 100644 index 0000000000..cda70dd5ea --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go @@ -0,0 +1,228 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/OptionalClaims +type OptionalClaims struct { + IDToken *string `json:"idToken,omitempty" form:"idToken,omitempty"` + AccessToken *string `json:"accessToken,omitempty" form:"accessToken,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *OptionalClaims) ApplyDefaults() { +} + +// #/components/schemas/Application +type Application struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` + OptionalClaims Nullable[ApplicationOptionalClaims] `json:"optionalClaims,omitempty" form:"optionalClaims,omitempty"` // Optional claims configuration +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Application) ApplyDefaults() { +} + +// #/components/schemas/Application/properties/optionalClaims +// Optional claims configuration +type ApplicationOptionalClaims struct { + OptionalClaims *OptionalClaims +} + +func (u ApplicationOptionalClaims) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.OptionalClaims != nil { + data, err := json.Marshal(u.OptionalClaims) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *ApplicationOptionalClaims) UnmarshalJSON(data []byte) error { + var v0 OptionalClaims + if err := json.Unmarshal(data, &v0); err == nil { + u.OptionalClaims = &v0 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ApplicationOptionalClaims) ApplyDefaults() { + if u.OptionalClaims != nil { + u.OptionalClaims.ApplyDefaults() + } +} + +// Nullable is a generic type that can distinguish between: +// - Field not provided (unspecified) +// - Field explicitly set to null +// - Field has a value +// +// This is implemented as a map[bool]T where: +// - Empty map: unspecified +// - map[false]T: explicitly null +// - map[true]T: has a value +type Nullable[T any] map[bool]T + +// NewNullableWithValue creates a Nullable with the given value. +func NewNullableWithValue[T any](value T) Nullable[T] { + return Nullable[T]{true: value} +} + +// NewNullNullable creates a Nullable that is explicitly null. +func NewNullNullable[T any]() Nullable[T] { + return Nullable[T]{false: *new(T)} +} + +// Get returns the value if set, or an error if null or unspecified. +func (n Nullable[T]) Get() (T, error) { + if v, ok := n[true]; ok { + return v, nil + } + var zero T + if n.IsNull() { + return zero, ErrNullableIsNull + } + return zero, ErrNullableNotSpecified +} + +// MustGet returns the value or panics if null or unspecified. +func (n Nullable[T]) MustGet() T { + v, err := n.Get() + if err != nil { + panic(err) + } + return v +} + +// Set assigns a value. +func (n *Nullable[T]) Set(value T) { + *n = Nullable[T]{true: value} +} + +// SetNull marks the field as explicitly null. +func (n *Nullable[T]) SetNull() { + *n = Nullable[T]{false: *new(T)} +} + +// SetUnspecified clears the field (as if it was never set). +func (n *Nullable[T]) SetUnspecified() { + *n = nil +} + +// IsNull returns true if the field is explicitly null. +func (n Nullable[T]) IsNull() bool { + if n == nil { + return false + } + _, ok := n[false] + return ok +} + +// IsSpecified returns true if the field was provided (either null or a value). +func (n Nullable[T]) IsSpecified() bool { + return len(n) > 0 +} + +// MarshalJSON implements json.Marshaler. +func (n Nullable[T]) MarshalJSON() ([]byte, error) { + if n.IsNull() { + return []byte("null"), nil + } + if v, ok := n[true]; ok { + return json.Marshal(v) + } + // Unspecified - this shouldn't be called if omitempty is used correctly + return []byte("null"), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *Nullable[T]) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + n.SetNull() + return nil + } + var v T + if err := json.Unmarshal(data, &v); err != nil { + return err + } + n.Set(v) + return nil +} + +// ErrNullableIsNull is returned when trying to get a value from a null Nullable. +var ErrNullableIsNull = errors.New("nullable value is null") + +// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. +var ErrNullableNotSpecified = errors.New("nullable value is not specified") + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/5SRQWvcMBSE7/oVAy7kkqy3KbnoVnrqaS+BnrXys/1a+T0hPbcsIf+92NnueqEQcrNH", + "M8ynUYPvtc6Ep/2jR5DToW9DSocef9hGqKQTVAiFetgpEwYSKsGogsWo9CHSy6trMJrl6tt2YBvn4y7q", + "1GrI/BC1o4Hk9oeXyto+7R9d4xr8GEneuqEFb/VjqDftVEgi3YMNddQ5dRcS18DGjadbQe8halvGndNM", + "EjJ7fNntd3vH0qt3gLEl8tcZ8EzVHPCbSmUVj8+rPQcbq8fLq4s6ZRUSq0u8xpGmsH4Ch2ysEtK3FHg6", + "a1h5PPT4k6KdpVw0UzGmiwng7ll/kVyFf8lqhWW4yCFGqvV979ecE8ewEH2QRMJE72Lof++6Ai5PuRWA", + "B3wq1HvcNe11vva8XXs7290m2VGNhddjf1kXcfUhqvQ8zGW94iYkc0rhuDyqlZnc3wAAAP//6uhqZ+MC", + "AAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types_test.go b/experimental/internal/codegen/test/issues/issue_502/output/types_test.go new file mode 100644 index 0000000000..c0f7f6bb71 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_502/output/types_test.go @@ -0,0 +1,107 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestAnyOfWithSingleRef verifies that anyOf with a single $ref generates +// correct types that can be used. +// https://github.com/oapi-codegen/oapi-codegen/issues/502 +func TestAnyOfWithSingleRef(t *testing.T) { + // OptionalClaims should be properly generated + claims := OptionalClaims{ + IDToken: ptrTo("id-token-value"), + AccessToken: ptrTo("access-token-value"), + } + + if *claims.IDToken != "id-token-value" { + t.Errorf("IDToken = %q, want %q", *claims.IDToken, "id-token-value") + } + if *claims.AccessToken != "access-token-value" { + t.Errorf("AccessToken = %q, want %q", *claims.AccessToken, "access-token-value") + } +} + +func TestApplicationWithAnyOfProperty(t *testing.T) { + // Application.OptionalClaims is an anyOf with a single ref + nullable: true + // It should be Nullable[ApplicationOptionalClaims] + app := Application{ + Name: ptrTo("my-app"), + OptionalClaims: NewNullableWithValue(ApplicationOptionalClaims{ + OptionalClaims: &OptionalClaims{ + IDToken: ptrTo("token"), + }, + }), + } + + if *app.Name != "my-app" { + t.Errorf("Name = %q, want %q", *app.Name, "my-app") + } + if !app.OptionalClaims.IsSpecified() { + t.Fatal("OptionalClaims should be specified") + } + optClaims := app.OptionalClaims.MustGet() + if optClaims.OptionalClaims == nil { + t.Fatal("OptionalClaims.OptionalClaims should not be nil") + } + if *optClaims.OptionalClaims.IDToken != "token" { + t.Errorf("IDToken = %q, want %q", *optClaims.OptionalClaims.IDToken, "token") + } +} + +func TestApplicationJSONRoundTrip(t *testing.T) { + original := Application{ + Name: ptrTo("test-app"), + OptionalClaims: NewNullableWithValue(ApplicationOptionalClaims{ + OptionalClaims: &OptionalClaims{ + IDToken: ptrTo("id"), + AccessToken: ptrTo("access"), + }, + }), + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded Application + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if *decoded.Name != *original.Name { + t.Errorf("Name mismatch: got %q, want %q", *decoded.Name, *original.Name) + } + if !decoded.OptionalClaims.IsSpecified() { + t.Fatal("OptionalClaims should be specified after round trip") + } + optClaims := decoded.OptionalClaims.MustGet() + if optClaims.OptionalClaims == nil { + t.Fatal("OptionalClaims.OptionalClaims should not be nil after round trip") + } +} + +func TestApplicationNullOptionalClaims(t *testing.T) { + // Test with explicitly null optional claims + app := Application{ + Name: ptrTo("null-test-app"), + OptionalClaims: NewNullNullable[ApplicationOptionalClaims](), + } + + if !app.OptionalClaims.IsNull() { + t.Error("OptionalClaims should be null") + } + + // Should marshal as null + data, err := json.Marshal(app) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + t.Logf("Marshaled with null optionalClaims: %s", string(data)) +} + +func ptrTo[T any](v T) *T { + return &v +} diff --git a/experimental/internal/codegen/test/issues/issue_502/spec.yaml b/experimental/internal/codegen/test/issues/issue_502/spec.yaml new file mode 100644 index 0000000000..04e5a324e8 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_502/spec.yaml @@ -0,0 +1,29 @@ +# Issue 502: anyOf/allOf with only one ref type generates interface{} +# https://github.com/oapi-codegen/oapi-codegen/issues/502 +# +# When anyOf or allOf has only one reference, it should generate +# the referenced type, not interface{}. +openapi: 3.0.0 +info: + title: Issue 502 Test + version: 1.0.0 +paths: {} +components: + schemas: + OptionalClaims: + type: object + properties: + idToken: + type: string + accessToken: + type: string + Application: + type: object + properties: + name: + type: string + optionalClaims: + anyOf: + - $ref: '#/components/schemas/OptionalClaims' + description: Optional claims configuration + nullable: true diff --git a/experimental/internal/codegen/test/issues/issue_52/doc.go b/experimental/internal/codegen/test/issues/issue_52/doc.go new file mode 100644 index 0000000000..f4646cbdb6 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_52/doc.go @@ -0,0 +1,5 @@ +// Package issue_52 tests that recursive types are handled properly. +// https://github.com/oapi-codegen/oapi-codegen/issues/52 +package issue_52 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go new file mode 100644 index 0000000000..72354dfa93 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go @@ -0,0 +1,87 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Document +type Document struct { + Fields map[string]any `json:"fields,omitempty" form:"fields,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Document) ApplyDefaults() { +} + +// #/components/schemas/Document/properties/fields +type DocumentFields = map[string]any + +// #/components/schemas/Value +type Value struct { + StringValue *string `json:"stringValue,omitempty" form:"stringValue,omitempty"` + ArrayValue *ArrayValue `json:"arrayValue,omitempty" form:"arrayValue,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Value) ApplyDefaults() { +} + +// #/components/schemas/ArrayValue +type ArrayValue = []Value + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/5xQTWvcMBC961c8sgWdarlbctEtUCihlJYeelfkWVupLQnNOHShP77Y3g/vJvQjOknz", + "3rwPbXDPPBJutxbfyI+FwxNB9pkYnYtNH2KrNuhEMltj2iDd+FD5NJjkcnjrU0MtxctHmBTZ3G7VRm3w", + "2f0g8FgI0jlBuTJxhRYjapBLylT6vUqZosvB4n1VV1sV4i5ZBTxR4ZCiha6runqnFSBBerKgn27IPSmg", + "IfYlZJl5vxSAVyXITjqePM1B2s5SLclyASaim2zum5P/R5IDWohzikx8pAN6W9f6/LyKevPl080K8ykK", + "RVnTAe1y7oOfXc0jp6gvcYB9R4O7ngJvCu0s9Mb4NOQUKQqbhcvmQ/LjQFG0OoOTwgFfxI6ko/T0dRbp", + "4ZH8sfLydxLWnXeB+obXeV5YnI5rmjDVcv3XF2T+VuG760fSM32+/mdKlhJie7F53l7A09iV4vbPqH8K", + "d3faWBLePVNYjGblwyQIDauA/9D9dwAAAP//+4PlsMkDAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types_test.go b/experimental/internal/codegen/test/issues/issue_52/output/types_test.go new file mode 100644 index 0000000000..7bb4f39267 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_52/output/types_test.go @@ -0,0 +1,64 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestRecursiveTypes verifies that recursive type definitions work correctly. +// https://github.com/oapi-codegen/oapi-codegen/issues/52 +func TestRecursiveTypes(t *testing.T) { + // Value references ArrayValue which is []Value - recursive + str := "test" + val := Value{ + StringValue: &str, + ArrayValue: &ArrayValue{ + {StringValue: &str}, + }, + } + + if *val.StringValue != "test" { + t.Errorf("StringValue = %q, want %q", *val.StringValue, "test") + } + if len(*val.ArrayValue) != 1 { + t.Errorf("ArrayValue length = %d, want 1", len(*val.ArrayValue)) + } +} + +func TestRecursiveJSONRoundTrip(t *testing.T) { + str := "test" + nested := "nested" + original := Value{ + StringValue: &str, + ArrayValue: &ArrayValue{ + {StringValue: &nested}, + }, + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded Value + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if *decoded.StringValue != *original.StringValue { + t.Errorf("StringValue mismatch: got %q, want %q", *decoded.StringValue, *original.StringValue) + } +} + +func TestDocumentWithRecursiveFields(t *testing.T) { + // Document.Fields is map[string]any (due to additionalProperties: $ref Value) + doc := Document{ + Fields: map[string]any{ + "key1": "value1", + }, + } + + if doc.Fields["key1"] != "value1" { + t.Errorf("Fields[key1] = %v, want %q", doc.Fields["key1"], "value1") + } +} diff --git a/experimental/internal/codegen/test/issues/issue_52/spec.yaml b/experimental/internal/codegen/test/issues/issue_52/spec.yaml new file mode 100644 index 0000000000..a29ee7a7be --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_52/spec.yaml @@ -0,0 +1,41 @@ +# Issue 52: Recursive types handling +# https://github.com/oapi-codegen/oapi-codegen/issues/52 +# +# Make sure that recursive types are handled properly +openapi: 3.0.2 +info: + version: '0.0.1' + title: example + description: | + Make sure that recursive types are handled properly +paths: + /example: + get: + operationId: exampleGet + responses: + '200': + description: "OK" + content: + 'application/json': + schema: + $ref: '#/components/schemas/Document' +components: + schemas: + Document: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/components/schemas/Value' + Value: + type: object + properties: + stringValue: + type: string + arrayValue: + $ref: '#/components/schemas/ArrayValue' + ArrayValue: + type: array + items: + $ref: '#/components/schemas/Value' diff --git a/experimental/internal/codegen/test/issues/issue_579/doc.go b/experimental/internal/codegen/test/issues/issue_579/doc.go new file mode 100644 index 0000000000..10d90fa7f5 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_579/doc.go @@ -0,0 +1,5 @@ +// Package issue_579 tests aliased types with date format. +// https://github.com/oapi-codegen/oapi-codegen/issues/579 +package issue_579 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go new file mode 100644 index 0000000000..071c05c0f4 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go @@ -0,0 +1,110 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" + "time" +) + +// #/components/schemas/Pet +type Pet struct { + Born *any `json:"born,omitempty" form:"born,omitempty"` + BornAt *Date `json:"born_at,omitempty" form:"born_at,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Pet) ApplyDefaults() { +} + +const DateFormat = "2006-01-02" + +type Date struct { + time.Time +} + +func (d Date) MarshalJSON() ([]byte, error) { + return json.Marshal(d.Format(DateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var dateStr string + err := json.Unmarshal(data, &dateStr) + if err != nil { + return err + } + parsed, err := time.Parse(DateFormat, dateStr) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +func (d Date) String() string { + return d.Format(DateFormat) +} + +func (d *Date) UnmarshalText(data []byte) error { + parsed, err := time.Parse(DateFormat, string(data)) + if err != nil { + return err + } + d.Time = parsed + return nil +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/2SSz86bMBDE7zzFiPTamLaKovhWqZfc8gaVYzbgCryWd9M/b18Z+ET8fZzY0c74N+AD", + "riJPwul8sfg+BSfUQ/8lEvwJOqJ3Snhwnp02B4yqSawxQ9DxeT96ng27FD577mmgWA+hBIs5nS8NJ4ou", + "BYv227E7dm0T4oNtA/ymLIGjxZeiN4AGncjuUFASbZLTUcq+SZPzNPLUUy4zMJCuLwAnyk4Dx2tvi37b", + "d7eNTJI4CsmbBfjadfsA9CQ+h6QLVPoQUB7PUSnqqwtQ+qsFLsRaB8SPNLv3KpaPbCGaQxwaz3PiSFEX", + "stWyQd72gquF77/I6yalXFpreK1051xRfMr0sGgPZj/FbEeY7Zf/cEptFfDTVQ0r2l1eb4Zdrskiv+TV", + "1JW1sv0PAAD//3OxuKeDAgAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types_test.go b/experimental/internal/codegen/test/issues/issue_579/output/types_test.go new file mode 100644 index 0000000000..895928b075 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_579/output/types_test.go @@ -0,0 +1,64 @@ +package output + +import ( + "encoding/json" + "testing" + "time" +) + +// TestAliasedDateType verifies that date format types work correctly. +// https://github.com/oapi-codegen/oapi-codegen/issues/579 +func TestDateType(t *testing.T) { + // Direct date type should use Date + date := Date{Time: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)} + + data, err := json.Marshal(date) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + if string(data) != `"2024-01-15"` { + t.Errorf("Marshal result = %s, want %q", string(data), "2024-01-15") + } + + var decoded Date + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if !decoded.Equal(date.Time) { + t.Errorf("Unmarshal result = %v, want %v", decoded.Time, date.Time) + } +} + +func TestPetWithDateFields(t *testing.T) { + // Pet has born_at as *Date (direct format: date) + date := Date{Time: time.Date(2020, 6, 15, 0, 0, 0, 0, time.UTC)} + pet := Pet{ + BornAt: &date, + } + + if pet.BornAt == nil { + t.Fatal("BornAt should not be nil") + } + if pet.BornAt.String() != "2020-06-15" { + t.Errorf("BornAt = %q, want %q", pet.BornAt.String(), "2020-06-15") + } +} + +// Note: The current implementation generates Born as *any instead of the ideal +// AliasedDate type. This is a known limitation with $ref to type aliases. +func TestPetBornFieldExists(t *testing.T) { + // Just verify the field exists and can hold a value + pet := Pet{ + Born: ptrTo[any]("2020-06-15"), + } + + if pet.Born == nil { + t.Fatal("Born should not be nil") + } +} + +func ptrTo[T any](v T) *T { + return &v +} diff --git a/experimental/internal/codegen/test/issues/issue_579/spec.yaml b/experimental/internal/codegen/test/issues/issue_579/spec.yaml new file mode 100644 index 0000000000..8baf490045 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_579/spec.yaml @@ -0,0 +1,30 @@ +# Issue 579: Aliased types with date format +# https://github.com/oapi-codegen/oapi-codegen/issues/579 +openapi: "3.0.0" +info: + version: 1.0.0 + title: Issue 579 test +paths: + /placeholder: + get: + operationId: getPlaceholder + responses: + 200: + description: placeholder + content: + text/plain: + schema: + type: string +components: + schemas: + Pet: + type: object + properties: + born: + $ref: "#/components/schemas/AliasedDate" + born_at: + type: string + format: date + AliasedDate: + type: string + format: date diff --git a/experimental/internal/codegen/test/issues/issue_697/doc.go b/experimental/internal/codegen/test/issues/issue_697/doc.go new file mode 100644 index 0000000000..3b3d314ae0 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_697/doc.go @@ -0,0 +1,5 @@ +// Package issue_697 tests that properties alongside allOf are included. +// https://github.com/oapi-codegen/oapi-codegen/issues/697 +package issue_697 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go new file mode 100644 index 0000000000..1a342a9e92 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go @@ -0,0 +1,81 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/YBase +type YBase struct { + BaseField *string `json:"baseField,omitempty" form:"baseField,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *YBase) ApplyDefaults() { +} + +// #/components/schemas/X +type X struct { + A *string `json:"a,omitempty" form:"a,omitempty"` + B *int `json:"b,omitempty" form:"b,omitempty"` + BaseField *string `json:"baseField,omitempty" form:"baseField,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *X) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/3yQwWrcMBCG73qKH1zIpbE3KSRExx4KPbWHQNvj2Jq1psiS0MwGSum7lyhZ3NKyt/Hv", + "bzTfzICPqifG3cO9x+dWKjcTVmSmBkrp0xHUGLLm0ji4AdGsqp+mVSye5nEp21SoyvVSAq+c//6Q57d1", + "unu4d4Mb8CVyBkGXyBshkmIuFs9jckDdBchgkaG0MRI/cXrrhp78wWgspxQwMyQv6RQ4QHKHVs7cyDjA", + "flQe3YDHKApRqGySqMEKuh1ubw63oyuVM1XxeDcexoOTfCzeASaW2O83wiOrOeCJm0rJHjcdr2RRPX7+", + "ckvZasmcTZ/bXzbtJfDtPSm/lOhaHmX+zou9RvtiZwiYSfmDcAp7dO5Va5LXHn89/+2X3NFrvGl89Lga", + "pt1repWaus/VheF0cWjX+5eQbLxy+9+avwMAAP//FjslWWwCAAA=", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types_test.go b/experimental/internal/codegen/test/issues/issue_697/output/types_test.go new file mode 100644 index 0000000000..f3d5263a93 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_697/output/types_test.go @@ -0,0 +1,58 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestXHasAllFields verifies that schema X has properties from both its own +// definition AND from the allOf reference to YBase. +// https://github.com/oapi-codegen/oapi-codegen/issues/697 +func TestXHasAllFields(t *testing.T) { + a := "a-value" + b := 42 + baseField := "base-value" + + x := X{ + A: &a, + B: &b, + BaseField: &baseField, + } + + // Verify all fields are accessible + if *x.A != "a-value" { + t.Errorf("X.A = %q, want %q", *x.A, "a-value") + } + if *x.B != 42 { + t.Errorf("X.B = %d, want %d", *x.B, 42) + } + if *x.BaseField != "base-value" { + t.Errorf("X.BaseField = %q, want %q", *x.BaseField, "base-value") + } +} + +func TestXJSONRoundTrip(t *testing.T) { + a := "a-value" + b := 42 + baseField := "base-value" + + original := X{ + A: &a, + B: &b, + BaseField: &baseField, + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded X + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if *decoded.A != *original.A || *decoded.B != *original.B || *decoded.BaseField != *original.BaseField { + t.Errorf("Round trip failed: got %+v, want %+v", decoded, original) + } +} diff --git a/experimental/internal/codegen/test/issues/issue_697/spec.yaml b/experimental/internal/codegen/test/issues/issue_697/spec.yaml new file mode 100644 index 0000000000..314044fc9b --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_697/spec.yaml @@ -0,0 +1,27 @@ +# Issue 697: Properties near allOf are ignored +# https://github.com/oapi-codegen/oapi-codegen/issues/697 +# +# When a schema has both allOf and properties at the same level, +# the properties should be included in the generated type. +# This is similar to issue 2102. +openapi: 3.0.0 +info: + title: Issue 697 Test + version: 1.0.0 +paths: {} +components: + schemas: + YBase: + type: object + properties: + baseField: + type: string + X: + allOf: + - $ref: '#/components/schemas/YBase' + properties: + a: + type: string + b: + type: integer + type: object diff --git a/experimental/internal/codegen/test/issues/issue_775/doc.go b/experimental/internal/codegen/test/issues/issue_775/doc.go new file mode 100644 index 0000000000..f97f08fec2 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_775/doc.go @@ -0,0 +1,5 @@ +// Package issue_775 tests that allOf with format specification works correctly. +// https://github.com/oapi-codegen/oapi-codegen/issues/775 +package issue_775 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go new file mode 100644 index 0000000000..1cd65cb493 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go @@ -0,0 +1,86 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/TestObject +type TestObject struct { + UUIDProperty *TestObjectUUIDProperty `json:"uuidProperty,omitempty" form:"uuidProperty,omitempty"` + DateProperty *TestObjectDateProperty `json:"dateProperty,omitempty" form:"dateProperty,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestObject) ApplyDefaults() { +} + +// #/components/schemas/TestObject/properties/uuidProperty +type TestObjectUUIDProperty struct { +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestObjectUUIDProperty) ApplyDefaults() { +} + +// #/components/schemas/TestObject/properties/dateProperty +type TestObjectDateProperty struct { +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *TestObjectDateProperty) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/6xQQW7bMBC88xUD61hYclEYAviDntxD+wBKWkvbSFyCu4phBPl7IFmOnXtunOHM7OwW", + "+K06E+r66BHG8XTGD5wlT8GQAyspdm2IiGKYKPcEjq1MKRg3I21K3YFyluwKDGZJfVX1bMPclK1MlYTE", + "+1Y66il+BbyM1qquj65wBf4px34rYYLQdQj3LgtGE5Rg10TQQeaxw0XyCy5sg8x2q6Clk0QxJPb4VR7K", + "g+N4Fu8AYxvJP9bFX1JzwCtlZYkeP1d5Cjaox9u7W9aUSNF0sWs70BTWJ1brqflPrd0w1lYesnIblbIk", + "ysakdxEwz9z9ufHXB3u3q2WO/RO93uJZB+y3i/g16/OrC0bfFbxkuY8AAAD//xKKQGYZAgAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types_test.go b/experimental/internal/codegen/test/issues/issue_775/output/types_test.go new file mode 100644 index 0000000000..c2efe59909 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_775/output/types_test.go @@ -0,0 +1,37 @@ +package output + +import ( + "testing" +) + +// TestAllOfWithFormatCompiles verifies that using allOf to add format +// specifications doesn't cause generation errors. +// https://github.com/oapi-codegen/oapi-codegen/issues/775 +// +// Note: The current implementation generates empty struct types for these +// properties instead of the ideal Go types (uuid.UUID for format:uuid, +// time.Time for format:date). This is a known limitation. +func TestAllOfWithFormatCompiles(t *testing.T) { + // The fact that this compiles proves the original issue is fixed + // (generation no longer errors on allOf + format) + obj := TestObject{ + UUIDProperty: &TestObjectUUIDProperty{}, + DateProperty: &TestObjectDateProperty{}, + } + + // Access the fields to ensure they exist + _ = obj.UUIDProperty + _ = obj.DateProperty +} + +// TestIdealBehavior documents the expected ideal behavior. +// Currently this would require changes to handle format-only allOf schemas. +func TestIdealBehavior(t *testing.T) { + t.Skip("TODO: allOf with format-only schemas should produce proper Go types (uuid.UUID, time.Time)") + + // Ideal behavior would be: + // type TestObject struct { + // UUIDProperty *uuid.UUID `json:"uuidProperty,omitempty"` + // DateProperty *time.Time `json:"dateProperty,omitempty"` + // } +} diff --git a/experimental/internal/codegen/test/issues/issue_775/spec.yaml b/experimental/internal/codegen/test/issues/issue_775/spec.yaml new file mode 100644 index 0000000000..353485dd5b --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_775/spec.yaml @@ -0,0 +1,22 @@ +# Issue 775: allOf + format raises "can not merge incompatible formats" error +# https://github.com/oapi-codegen/oapi-codegen/issues/775 +# +# Using allOf to add a format to a base type should work without errors. +openapi: 3.0.0 +info: + title: Issue 775 Test + version: 1.0.0 +paths: {} +components: + schemas: + TestObject: + type: object + properties: + uuidProperty: + type: string + allOf: + - format: uuid + dateProperty: + type: string + allOf: + - format: date diff --git a/experimental/internal/codegen/test/issues/issue_832/doc.go b/experimental/internal/codegen/test/issues/issue_832/doc.go new file mode 100644 index 0000000000..a1e8c49610 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_832/doc.go @@ -0,0 +1,5 @@ +// Package issue_832 tests x-go-type-name override for enum types. +// https://github.com/oapi-codegen/oapi-codegen/issues/832 +package issue_832 + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go new file mode 100644 index 0000000000..d9dd314469 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go @@ -0,0 +1,91 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Document +type Document struct { + Name *string `json:"name,omitempty" form:"name,omitempty"` + Status *string `json:"status,omitempty" form:"status,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *Document) ApplyDefaults() { +} + +// #/components/schemas/Document/properties/status +type Document_Status string + +const ( + Document_Status_one Document_Status = "one" + Document_Status_two Document_Status = "two" + Document_Status_three Document_Status = "three" + Document_Status_four Document_Status = "four" +) + +// #/components/schemas/DocumentStatus +type DocumentStatus struct { + Value *string `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *DocumentStatus) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/9RSPYvbQBDt9Sse54AaW1Lk5tg6EI4UKS5dCGFvPZb2sHaWnZFzgfz4IMkfkiHE7XWa", + "maf3wb4VnkR6wuO2NnjbNLzR35E2wXaEPSdQ6DsMK8lWaFWjmLJsvLb9S+G4K9lGv3G8o4bCcvADr5SP", + "2zrjSMFGb7AtqqLOfNizyYAjJfEcDPKqqIqPeQao1wMZ0Jvt4oEyYEfiko864v5kAPCNRG+t8pFS8ruZ", + "55g4UlJPkkWrrQyC5YnXjDwN6fQBDFA7aDztLuKfSU/XRBI5CMkZDuR1VeXX8cbnw9cvD7Ob46AUdA4H", + "chvjwbtRtXwVDvnyDohrqbO3W+BDor1Bviodd5EDBZVywkr5iV3fUdB8lra+N279fvM+q9Ve8uwKGXhO", + "qInyDD0LDOUx4JdXcueHvnbm6mKo19zT9Jto8qG5rGWUn8OW/TQX9Z+T0/8RYiyxwXcOtIb+4jW0TURr", + "7LlPPxaBnhfid8Y62kP/71x/AwAA//+qyWhEFgQAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types_test.go b/experimental/internal/codegen/test/issues/issue_832/output/types_test.go new file mode 100644 index 0000000000..8537eb4648 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_832/output/types_test.go @@ -0,0 +1,62 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestEnumTypeGeneration verifies that enum types in properties are generated. +// https://github.com/oapi-codegen/oapi-codegen/issues/832 +// +// Note: The x-go-type-name extension is not currently supported. The enum type +// is generated with a name derived from the property path rather than the +// specified x-go-type-name. +func TestEnumTypeGeneration(t *testing.T) { + // Enum constants should exist + _ = Document_Status_one + _ = Document_Status_two + _ = Document_Status_three + _ = Document_Status_four + + if string(Document_Status_one) != "one" { + t.Errorf("one = %q, want %q", Document_Status_one, "one") + } +} + +func TestDocumentWithStatus(t *testing.T) { + name := "test" + status := "one" + doc := Document{ + Name: &name, + Status: &status, + } + + data, err := json.Marshal(doc) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded Document + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if *decoded.Name != *doc.Name { + t.Errorf("Name = %q, want %q", *decoded.Name, *doc.Name) + } + if *decoded.Status != *doc.Status { + t.Errorf("Status = %q, want %q", *decoded.Status, *doc.Status) + } +} + +func TestDocumentStatusSchema(t *testing.T) { + // There's also a DocumentStatus schema (separate from the enum property) + value := "test-value" + ds := DocumentStatus{ + Value: &value, + } + + if *ds.Value != "test-value" { + t.Errorf("Value = %q, want %q", *ds.Value, "test-value") + } +} diff --git a/experimental/internal/codegen/test/issues/issue_832/spec.yaml b/experimental/internal/codegen/test/issues/issue_832/spec.yaml new file mode 100644 index 0000000000..fe2e387fdb --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_832/spec.yaml @@ -0,0 +1,45 @@ +# Issue 832: x-go-type-name for enum types +# https://github.com/oapi-codegen/oapi-codegen/issues/832 +openapi: 3.0.2 +info: + version: '0.0.1' + title: example + description: | + Test x-go-type-name override for enum properties +paths: + /example: + get: + operationId: exampleGet + responses: + '200': + description: "OK" + content: + 'application/json': + schema: + $ref: '#/components/schemas/Document' + /example2: + get: + operationId: exampleGet2 + responses: + '200': + description: "OK" + content: + 'application/json': + schema: + $ref: '#/components/schemas/DocumentStatus' +components: + schemas: + Document: + type: object + properties: + name: + type: string + status: + x-go-type-name: Document_Status + type: string + enum: [one, two, three, four] + DocumentStatus: + type: object + properties: + value: + type: string diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go new file mode 100644 index 0000000000..db5bcd0016 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go @@ -0,0 +1,5 @@ +// Package issue_head_digit_operation_id tests operation IDs starting with digits. +// https://github.com/oapi-codegen/oapi-codegen/issues/head-digit-of-operation-id +package issue_head_digit_operation_id + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go new file mode 100644 index 0000000000..3bbe71257a --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go @@ -0,0 +1,69 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/paths//3gpp/foo/get/responses/200/content/application/json/schema +type N3GPPFooJSONResponse struct { + Value *string `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *N3GPPFooJSONResponse) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/2yPsXLqMBBFe33FHdMbP+hUM48wKaDIDyj2Ii9xtBrtQiZ/nzGBsUmiStK5ujq7wE71", + "TB77TCUYS8JuA7VQjFPEB1uPjiObW+CF1BTWB4PM0oqB3wjVens4/BepECmNlHAJA3fYCrijZHxkKuok", + "UwqZPdZ1U68cp6N4B1yoKEvyqJq6qf9VDjC2gTyeKHTYjA6PkqOOy8F6Hd8v1zHn5VGuZUAk+95gct11", + "HjfJGyqkWZKS3rPAqmmmA9CRtoWzXdX2zzPSSjJKNg8DIeeB2+tvy5NKeqSAtj29h5+3gH1m8pDXE7X2", + "C+YyjmA815zWJQxn+gvcW9UKp+i+AgAA//9y+0ZQ6gEAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go new file mode 100644 index 0000000000..df0bc5f952 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go @@ -0,0 +1,50 @@ +package output + +import ( + "encoding/json" + "testing" +) + +// TestOperationIdStartingWithDigit verifies that operation IDs starting with +// digits generate valid Go identifiers with an N prefix. +func TestOperationIdStartingWithDigit(t *testing.T) { + // The operationId is "3GPPFoo" which should generate N3GPPFooJSONResponse + // (N prefix added to make it a valid Go identifier) + value := "test" + response := N3GPPFooJSONResponse{ + Value: &value, + } + + if *response.Value != "test" { + t.Errorf("Value = %q, want %q", *response.Value, "test") + } +} + +func TestN3GPPFooJSONRoundTrip(t *testing.T) { + value := "test-value" + original := N3GPPFooJSONResponse{ + Value: &value, + } + + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + + var decoded N3GPPFooJSONResponse + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if *decoded.Value != *original.Value { + t.Errorf("Value = %q, want %q", *decoded.Value, *original.Value) + } +} + +// TestTypeNameIsValid ensures the type name is a valid Go identifier +func TestTypeNameIsValid(t *testing.T) { + // This test passes if it compiles - the type N3GPPFooJSONResponse + // must be a valid Go identifier + var _ N3GPPFooJSONResponse + var _ N3GPPFooJSONResponse +} diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml new file mode 100644 index 0000000000..5bcd0f7d70 --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml @@ -0,0 +1,20 @@ +# Issue: Operation ID starting with digit +# Tests that operation IDs like "3GPPFoo" generate valid Go identifiers +openapi: 3.0.2 +info: + version: "0.0.1" + title: Head Digit Operation ID Test +paths: + /3gpp/foo: + get: + operationId: 3GPPFoo + responses: + 200: + description: OK + content: + application/json: + schema: + type: object + properties: + value: + type: string diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go new file mode 100644 index 0000000000..e40f41cd2e --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go @@ -0,0 +1,5 @@ +// Package issue_illegal_enum_names tests enum constant generation with edge cases. +// This tests various edge cases like empty strings, spaces, hyphens, leading digits, etc. +package issue_illegal_enum_names + +//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go new file mode 100644 index 0000000000..ac2d373dde --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go @@ -0,0 +1,80 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/Bar +type Bar string + +const ( + Bar_Value Bar = "" + Bar_Foo Bar = "Foo" + Bar_Bar Bar = "Bar" + Bar_Foo_Bar Bar = "Foo Bar" + Bar_Foo_Bar_1 Bar = "Foo-Bar" + Bar_Foo_1 Bar = "1Foo" + Bar__Foo Bar = " Foo" + Bar__Foo_ Bar = " Foo " + Bar__Foo__1 Bar = "_Foo_" + Bar_Value_1 Bar = "1" +) + +// #/paths//foo/get/responses/200/content/application/json/schema +type GetFooJSONResponse = []Bar + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/2SRQYujQBCF7/0rHpMFT6PO7M1jYAfCwu5l76ExFdOLVjVdlSz590urQU1u1veq3ie6", + "w0H1Sg0OfU+d70F8HcB+IHU7/CE1nVArrObZ0BFT8haE8S/YBTefglwVdOoIrVdSJ5HYx9Dge1mXn84F", + "PkvjAAvWr1Q/cu+vrBpFDrhR0iDcoC7rsnYuertovqzOMjYAHdn0AEicX+RwajL/EpmTRBqFlfSxCnzW", + "9TIAJ9I2hWij7ffPVdIKG7GtlwEfYx/aUVb9VeFtCmh7ocE/U8DukRr4lPz9JQtGg76eAN8SnRsUu6qV", + "IQoTm1aTQKu9T4VzS5Dv52yq2vv06JzkailwN6P8KxflO4piNSzfL097n7bZK3nfko9tQZFXimeANTl+", + "iRxX89vHm/sfAAD//5W/OQySAgAA", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go new file mode 100644 index 0000000000..65a49f009f --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go @@ -0,0 +1,51 @@ +package output + +import ( + "testing" +) + +// TestIllegalEnumNames verifies that enum constants with various edge case values +// are generated with valid Go identifiers. +func TestIllegalEnumNames(t *testing.T) { + // All these enum constants should exist and have valid Go names + tests := []struct { + name string + constant Bar + value string + }{ + {"empty string", Bar_Value, ""}, + {"Foo", Bar_Foo, "Foo"}, + {"Bar", Bar_Bar, "Bar"}, + {"Foo Bar (with space)", Bar_Foo_Bar, "Foo Bar"}, + {"Foo-Bar (with hyphen)", Bar_Foo_Bar_1, "Foo-Bar"}, + {"1Foo (leading digit)", Bar_Foo_1, "1Foo"}, + {" Foo (leading space)", Bar__Foo, " Foo"}, + {" Foo (leading and trailing space)", Bar__Foo_, " Foo "}, + {"_Foo_ (underscores)", Bar__Foo__1, "_Foo_"}, + {"1 (just digit)", Bar_Value_1, "1"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if string(tt.constant) != tt.value { + t.Errorf("constant %q = %q, want %q", tt.name, tt.constant, tt.value) + } + }) + } +} + +func TestBarCanBeUsedInSlice(t *testing.T) { + // The response type is []Bar + response := GetFooJSONResponse{ + Bar_Foo, + Bar_Bar, + Bar_Value, // empty string + } + + if len(response) != 3 { + t.Errorf("response length = %d, want 3", len(response)) + } + if response[0] != "Foo" { + t.Errorf("response[0] = %q, want %q", response[0], "Foo") + } +} diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml new file mode 100644 index 0000000000..5d80f246cf --- /dev/null +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml @@ -0,0 +1,37 @@ +# Issue: Illegal enum names +# Tests enum constant generation with various edge cases +openapi: 3.0.2 + +info: + title: Illegal Enum Names Test + version: 0.0.0 + +paths: + /foo: + get: + operationId: getFoo + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Bar' + +components: + schemas: + Bar: + type: string + enum: + - '' + - Foo + - Bar + - Foo Bar + - Foo-Bar + - 1Foo + - ' Foo' + - ' Foo ' + - _Foo_ + - "1" diff --git a/experimental/internal/codegen/test/nested_aggregate/doc.go b/experimental/internal/codegen/test/nested_aggregate/doc.go new file mode 100644 index 0000000000..6d934ad0d9 --- /dev/null +++ b/experimental/internal/codegen/test/nested_aggregate/doc.go @@ -0,0 +1,3 @@ +package nested_aggregate + +//go:generate go run ../../../../cmd/oapi-codegen -package output -output output/nested_aggregate.gen.go nested_aggregate.yaml diff --git a/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml b/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml new file mode 100644 index 0000000000..7a9c081ec2 --- /dev/null +++ b/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml @@ -0,0 +1,62 @@ +openapi: "3.1.0" +info: + title: Nested Aggregate Test + version: "1.0" +paths: {} +components: + schemas: + # Case 1: Array with anyOf items + ArrayOfAnyOf: + type: array + items: + anyOf: + - type: string + - type: object + properties: + id: + type: integer + + # Case 2: Object with anyOf property + ObjectWithAnyOfProperty: + type: object + properties: + value: + anyOf: + - type: string + - type: integer + + # Case 3: Object with oneOf property containing inline objects + ObjectWithOneOfProperty: + type: object + properties: + variant: + oneOf: + - type: object + properties: + kind: + type: string + name: + type: string + - type: object + properties: + kind: + type: string + count: + type: integer + + # Case 4: allOf containing oneOf + AllOfWithOneOf: + allOf: + - type: object + properties: + base: + type: string + - oneOf: + - type: object + properties: + optionA: + type: boolean + - type: object + properties: + optionB: + type: integer diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go new file mode 100644 index 0000000000..8e9cb4c44b --- /dev/null +++ b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go @@ -0,0 +1,400 @@ +// Code generated by oapi-codegen; DO NOT EDIT. + +package output + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "sync" +) + +// #/components/schemas/ArrayOfAnyOf +type ArrayOfAnyOf = []ArrayOfAnyOfItem + +// #/components/schemas/ArrayOfAnyOf/items +type ArrayOfAnyOfItem struct { + String0 *string + ArrayOfAnyOfAnyOf1 *ArrayOfAnyOfAnyOf1 +} + +func (u ArrayOfAnyOfItem) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.ArrayOfAnyOfAnyOf1 != nil { + data, err := json.Marshal(u.ArrayOfAnyOfAnyOf1) + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err == nil { + for k, v := range m { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (u *ArrayOfAnyOfItem) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 ArrayOfAnyOfAnyOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.ArrayOfAnyOfAnyOf1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ArrayOfAnyOfItem) ApplyDefaults() { + if u.ArrayOfAnyOfAnyOf1 != nil { + u.ArrayOfAnyOfAnyOf1.ApplyDefaults() + } +} + +// #/components/schemas/ArrayOfAnyOf/items/anyOf/1 +type ArrayOfAnyOfAnyOf1 struct { + ID *int `json:"id,omitempty" form:"id,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ArrayOfAnyOfAnyOf1) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithAnyOfProperty +type ObjectWithAnyOfProperty struct { + Value *ObjectWithAnyOfPropertyValue `json:"value,omitempty" form:"value,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithAnyOfProperty) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithAnyOfProperty/properties/value +type ObjectWithAnyOfPropertyValue struct { + String0 *string + Int1 *int +} + +func (u ObjectWithAnyOfPropertyValue) MarshalJSON() ([]byte, error) { + if u.String0 != nil { + return json.Marshal(u.String0) + } + if u.Int1 != nil { + return json.Marshal(u.Int1) + } + return []byte("null"), nil +} + +func (u *ObjectWithAnyOfPropertyValue) UnmarshalJSON(data []byte) error { + var v0 string + if err := json.Unmarshal(data, &v0); err == nil { + u.String0 = &v0 + } + + var v1 int + if err := json.Unmarshal(data, &v1); err == nil { + u.Int1 = &v1 + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ObjectWithAnyOfPropertyValue) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithOneOfProperty +type ObjectWithOneOfProperty struct { + Variant *ObjectWithOneOfPropertyVariant `json:"variant,omitempty" form:"variant,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithOneOfProperty) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithOneOfProperty/properties/variant +type ObjectWithOneOfPropertyVariant struct { + ObjectWithOneOfPropertyVariantOneOf0 *ObjectWithOneOfPropertyVariantOneOf0 + ObjectWithOneOfPropertyVariantOneOf1 *ObjectWithOneOfPropertyVariantOneOf1 +} + +func (u ObjectWithOneOfPropertyVariant) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.ObjectWithOneOfPropertyVariantOneOf0 != nil { + count++ + data, err = json.Marshal(u.ObjectWithOneOfPropertyVariantOneOf0) + if err != nil { + return nil, err + } + } + if u.ObjectWithOneOfPropertyVariantOneOf1 != nil { + count++ + data, err = json.Marshal(u.ObjectWithOneOfPropertyVariantOneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("ObjectWithOneOfPropertyVariant: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *ObjectWithOneOfPropertyVariant) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 ObjectWithOneOfPropertyVariantOneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.ObjectWithOneOfPropertyVariantOneOf0 = &v0 + successCount++ + } + + var v1 ObjectWithOneOfPropertyVariantOneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.ObjectWithOneOfPropertyVariantOneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("ObjectWithOneOfPropertyVariant: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *ObjectWithOneOfPropertyVariant) ApplyDefaults() { + if u.ObjectWithOneOfPropertyVariantOneOf0 != nil { + u.ObjectWithOneOfPropertyVariantOneOf0.ApplyDefaults() + } + if u.ObjectWithOneOfPropertyVariantOneOf1 != nil { + u.ObjectWithOneOfPropertyVariantOneOf1.ApplyDefaults() + } +} + +// #/components/schemas/ObjectWithOneOfProperty/properties/variant/oneOf/0 +type ObjectWithOneOfPropertyVariantOneOf0 struct { + Kind *string `json:"kind,omitempty" form:"kind,omitempty"` + Name *string `json:"name,omitempty" form:"name,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithOneOfPropertyVariantOneOf0) ApplyDefaults() { +} + +// #/components/schemas/ObjectWithOneOfProperty/properties/variant/oneOf/1 +type ObjectWithOneOfPropertyVariantOneOf1 struct { + Kind *string `json:"kind,omitempty" form:"kind,omitempty"` + Count *int `json:"count,omitempty" form:"count,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *ObjectWithOneOfPropertyVariantOneOf1) ApplyDefaults() { +} + +// #/components/schemas/AllOfWithOneOf +type AllOfWithOneOf struct { + Base *string `json:"base,omitempty" form:"base,omitempty"` + AllOfWithOneOfAllOf1 *AllOfWithOneOfAllOf1 `json:"-"` +} + +func (s AllOfWithOneOf) MarshalJSON() ([]byte, error) { + result := make(map[string]any) + + if s.Base != nil { + result["base"] = s.Base + } + + if s.AllOfWithOneOfAllOf1 != nil { + unionData, err := json.Marshal(s.AllOfWithOneOfAllOf1) + if err != nil { + return nil, err + } + var unionMap map[string]any + if err := json.Unmarshal(unionData, &unionMap); err == nil { + for k, v := range unionMap { + result[k] = v + } + } + } + + return json.Marshal(result) +} + +func (s *AllOfWithOneOf) UnmarshalJSON(data []byte) error { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if v, ok := raw["base"]; ok { + var val string + if err := json.Unmarshal(v, &val); err != nil { + return err + } + s.Base = &val + } + + var AllOfWithOneOfAllOf1Val AllOfWithOneOfAllOf1 + if err := json.Unmarshal(data, &AllOfWithOneOfAllOf1Val); err != nil { + return err + } + s.AllOfWithOneOfAllOf1 = &AllOfWithOneOfAllOf1Val + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithOneOf) ApplyDefaults() { +} + +// #/components/schemas/AllOfWithOneOf/allOf/1 +type AllOfWithOneOfAllOf1 struct { + AllOfWithOneOfAllOf1OneOf0 *AllOfWithOneOfAllOf1OneOf0 + AllOfWithOneOfAllOf1OneOf1 *AllOfWithOneOfAllOf1OneOf1 +} + +func (u AllOfWithOneOfAllOf1) MarshalJSON() ([]byte, error) { + var count int + var data []byte + var err error + + if u.AllOfWithOneOfAllOf1OneOf0 != nil { + count++ + data, err = json.Marshal(u.AllOfWithOneOfAllOf1OneOf0) + if err != nil { + return nil, err + } + } + if u.AllOfWithOneOfAllOf1OneOf1 != nil { + count++ + data, err = json.Marshal(u.AllOfWithOneOfAllOf1OneOf1) + if err != nil { + return nil, err + } + } + + if count != 1 { + return nil, fmt.Errorf("AllOfWithOneOfAllOf1: exactly one member must be set, got %d", count) + } + + return data, nil +} + +func (u *AllOfWithOneOfAllOf1) UnmarshalJSON(data []byte) error { + var successCount int + + var v0 AllOfWithOneOfAllOf1OneOf0 + if err := json.Unmarshal(data, &v0); err == nil { + u.AllOfWithOneOfAllOf1OneOf0 = &v0 + successCount++ + } + + var v1 AllOfWithOneOfAllOf1OneOf1 + if err := json.Unmarshal(data, &v1); err == nil { + u.AllOfWithOneOfAllOf1OneOf1 = &v1 + successCount++ + } + + if successCount != 1 { + return fmt.Errorf("AllOfWithOneOfAllOf1: expected exactly one type to match, got %d", successCount) + } + + return nil +} + +// ApplyDefaults sets default values for fields that are nil. +func (u *AllOfWithOneOfAllOf1) ApplyDefaults() { + if u.AllOfWithOneOfAllOf1OneOf0 != nil { + u.AllOfWithOneOfAllOf1OneOf0.ApplyDefaults() + } + if u.AllOfWithOneOfAllOf1OneOf1 != nil { + u.AllOfWithOneOfAllOf1OneOf1.ApplyDefaults() + } +} + +// #/components/schemas/AllOfWithOneOf/allOf/1/oneOf/0 +type AllOfWithOneOfAllOf1OneOf0 struct { + OptionA *bool `json:"optionA,omitempty" form:"optionA,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithOneOfAllOf1OneOf0) ApplyDefaults() { +} + +// #/components/schemas/AllOfWithOneOf/allOf/1/oneOf/1 +type AllOfWithOneOfAllOf1OneOf1 struct { + OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` +} + +// ApplyDefaults sets default values for fields that are nil. +func (s *AllOfWithOneOfAllOf1OneOf1) ApplyDefaults() { +} + +// Base64-encoded, gzip-compressed OpenAPI spec. +var swaggerSpecJSON = []string{ + "H4sIAAAAAAAC/7yTQY/TMBCF7/kVT+W8K5bl5FvgTjggcXbTSTKQjC17WlQh/juKk9KkTVqBKnpq5nnG", + "75uXOE9iPRtsXp9fnt9uMpbKmQxQ1pYMPlFU2iGv60C1VcIXipoBBwqRnRhsUpe32kSDn7+y0nXeCYnG", + "fkosG+ps+gu8wUcbCS8GeQj2iB+sDawciwqs1MV0KElFlffloQ3QoycD2ytjJZ0/yRiGnB+Bp7EnamCp", + "FwS3/UalTgTAB+cpKFM0szrAu8vKyROLUk0hm/K9MyjS9CngOHzwP8hfWZuE+XnU5rgzh0veDrbd09TY", + "1RZu7OEsLSG8zhGc0AQBpRO1LCw1WFoWGr3GC7iib/tnuMBWdEqTXCzjLaR5K0/gO8tCpljfVv8T29Ff", + "Nf1fe6Xbzxd2/1V9b2DbtqimkaY1D59iL/0J8jQ5NZyvWWVc49vaeLXFRa6nhybuvLKTfH0/W+dasvLI", + "2z7cT+N3AAAA//8nzKKtgAUAAA==", +} + +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") + raw, err := base64.StdEncoding.DecodeString(joined) + if err != nil { + return nil, fmt.Errorf("decoding base64: %w", err) + } + r, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, fmt.Errorf("creating gzip reader: %w", err) + } + defer r.Close() + var out bytes.Buffer + if _, err := out.ReadFrom(r); err != nil { + return nil, fmt.Errorf("decompressing: %w", err) + } + return out.Bytes(), nil +} + +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { + var cached []byte + var cachedErr error + var once sync.Once + return func() ([]byte, error) { + once.Do(func() { + cached, cachedErr = decodeSwaggerSpec() + }) + return cached, cachedErr + } +} + +var swaggerSpec = decodeSwaggerSpecCached() + +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() +} diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go new file mode 100644 index 0000000000..e70e8cb49e --- /dev/null +++ b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go @@ -0,0 +1,332 @@ +package output + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ptr[T any](v T) *T { + return &v +} + +// TestArrayOfAnyOf tests marshaling/unmarshaling of arrays with anyOf items +func TestArrayOfAnyOf(t *testing.T) { + t.Run("unmarshal string item", func(t *testing.T) { + input := `["hello", "world"]` + var arr ArrayOfAnyOf + err := json.Unmarshal([]byte(input), &arr) + require.NoError(t, err) + require.Len(t, arr, 2) + + // String items should populate the string field + assert.NotNil(t, arr[0].String0) + assert.Equal(t, "hello", *arr[0].String0) + assert.NotNil(t, arr[1].String0) + assert.Equal(t, "world", *arr[1].String0) + }) + + t.Run("unmarshal object item", func(t *testing.T) { + input := `[{"id": 42}]` + var arr ArrayOfAnyOf + err := json.Unmarshal([]byte(input), &arr) + require.NoError(t, err) + require.Len(t, arr, 1) + + // Object item should populate the object field + assert.NotNil(t, arr[0].ArrayOfAnyOfAnyOf1) + assert.NotNil(t, arr[0].ArrayOfAnyOfAnyOf1.ID) + assert.Equal(t, 42, *arr[0].ArrayOfAnyOfAnyOf1.ID) + }) + + t.Run("unmarshal mixed items", func(t *testing.T) { + input := `["hello", {"id": 1}, "world", {"id": 2}]` + var arr ArrayOfAnyOf + err := json.Unmarshal([]byte(input), &arr) + require.NoError(t, err) + require.Len(t, arr, 4) + + assert.NotNil(t, arr[0].String0) + assert.Equal(t, "hello", *arr[0].String0) + + assert.NotNil(t, arr[1].ArrayOfAnyOfAnyOf1) + assert.Equal(t, 1, *arr[1].ArrayOfAnyOfAnyOf1.ID) + + assert.NotNil(t, arr[2].String0) + assert.Equal(t, "world", *arr[2].String0) + + assert.NotNil(t, arr[3].ArrayOfAnyOfAnyOf1) + assert.Equal(t, 2, *arr[3].ArrayOfAnyOfAnyOf1.ID) + }) + + t.Run("marshal string item", func(t *testing.T) { + arr := ArrayOfAnyOf{ + {String0: ptr("hello")}, + } + data, err := json.Marshal(arr) + require.NoError(t, err) + assert.JSONEq(t, `["hello"]`, string(data)) + }) + + t.Run("marshal object item", func(t *testing.T) { + arr := ArrayOfAnyOf{ + {ArrayOfAnyOfAnyOf1: &ArrayOfAnyOfAnyOf1{ID: ptr(42)}}, + } + data, err := json.Marshal(arr) + require.NoError(t, err) + assert.JSONEq(t, `[{"id": 42}]`, string(data)) + }) + + t.Run("round trip mixed", func(t *testing.T) { + original := ArrayOfAnyOf{ + {String0: ptr("test")}, + {ArrayOfAnyOfAnyOf1: &ArrayOfAnyOfAnyOf1{ID: ptr(99)}}, + } + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded ArrayOfAnyOf + err = json.Unmarshal(data, &decoded) + require.NoError(t, err) + + require.Len(t, decoded, 2) + assert.Equal(t, "test", *decoded[0].String0) + assert.Equal(t, 99, *decoded[1].ArrayOfAnyOfAnyOf1.ID) + }) +} + +// TestObjectWithAnyOfProperty tests marshaling/unmarshaling of objects with anyOf properties +func TestObjectWithAnyOfProperty(t *testing.T) { + t.Run("unmarshal string value", func(t *testing.T) { + input := `{"value": "hello"}` + var obj ObjectWithAnyOfProperty + err := json.Unmarshal([]byte(input), &obj) + require.NoError(t, err) + + require.NotNil(t, obj.Value) + assert.NotNil(t, obj.Value.String0) + assert.Equal(t, "hello", *obj.Value.String0) + }) + + t.Run("unmarshal integer value", func(t *testing.T) { + input := `{"value": 42}` + var obj ObjectWithAnyOfProperty + err := json.Unmarshal([]byte(input), &obj) + require.NoError(t, err) + + require.NotNil(t, obj.Value) + assert.NotNil(t, obj.Value.Int1) + assert.Equal(t, 42, *obj.Value.Int1) + }) + + t.Run("marshal string value", func(t *testing.T) { + obj := ObjectWithAnyOfProperty{ + Value: &ObjectWithAnyOfPropertyValue{ + String0: ptr("hello"), + }, + } + data, err := json.Marshal(obj) + require.NoError(t, err) + assert.JSONEq(t, `{"value": "hello"}`, string(data)) + }) + + t.Run("marshal integer value", func(t *testing.T) { + obj := ObjectWithAnyOfProperty{ + Value: &ObjectWithAnyOfPropertyValue{ + Int1: ptr(42), + }, + } + data, err := json.Marshal(obj) + require.NoError(t, err) + assert.JSONEq(t, `{"value": 42}`, string(data)) + }) + + t.Run("round trip string", func(t *testing.T) { + original := ObjectWithAnyOfProperty{ + Value: &ObjectWithAnyOfPropertyValue{String0: ptr("test")}, + } + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded ObjectWithAnyOfProperty + err = json.Unmarshal(data, &decoded) + require.NoError(t, err) + + require.NotNil(t, decoded.Value) + assert.Equal(t, "test", *decoded.Value.String0) + }) +} + +// TestObjectWithOneOfProperty tests marshaling/unmarshaling of objects with oneOf properties +func TestObjectWithOneOfProperty(t *testing.T) { + t.Run("unmarshal ambiguous input errors", func(t *testing.T) { + // Both variants have optional "kind" field, so this JSON matches both + // oneOf requires exactly one match, so this should error + input := `{"variant": {"kind": "person", "name": "Alice"}}` + var obj ObjectWithOneOfProperty + err := json.Unmarshal([]byte(input), &obj) + require.Error(t, err) + assert.Contains(t, err.Error(), "expected exactly one type to match, got 2") + }) + + t.Run("unmarshal unambiguous variant 0", func(t *testing.T) { + // Only variant 0 has "name" as a field that can be set + // But since all fields are optional, both variants still match + // This demonstrates why discriminators are important for oneOf + input := `{"variant": {"name": "Alice"}}` + var obj ObjectWithOneOfProperty + err := json.Unmarshal([]byte(input), &obj) + // Still ambiguous because both variants can unmarshal (missing fields are just nil) + require.Error(t, err) + }) + + t.Run("unmarshal unambiguous variant 1", func(t *testing.T) { + // Only variant 1 has "count" field + // But since all fields are optional, both variants still match + input := `{"variant": {"count": 10}}` + var obj ObjectWithOneOfProperty + err := json.Unmarshal([]byte(input), &obj) + // Still ambiguous because both variants can unmarshal (missing fields are just nil) + require.Error(t, err) + }) + + t.Run("marshal variant 0", func(t *testing.T) { + obj := ObjectWithOneOfProperty{ + Variant: &ObjectWithOneOfPropertyVariant{ + ObjectWithOneOfPropertyVariantOneOf0: &ObjectWithOneOfPropertyVariantOneOf0{ + Kind: ptr("person"), + Name: ptr("Alice"), + }, + }, + } + data, err := json.Marshal(obj) + require.NoError(t, err) + assert.JSONEq(t, `{"variant": {"kind": "person", "name": "Alice"}}`, string(data)) + }) + + t.Run("marshal variant 1", func(t *testing.T) { + obj := ObjectWithOneOfProperty{ + Variant: &ObjectWithOneOfPropertyVariant{ + ObjectWithOneOfPropertyVariantOneOf1: &ObjectWithOneOfPropertyVariantOneOf1{ + Kind: ptr("counter"), + Count: ptr(10), + }, + }, + } + data, err := json.Marshal(obj) + require.NoError(t, err) + assert.JSONEq(t, `{"variant": {"kind": "counter", "count": 10}}`, string(data)) + }) + + t.Run("marshal fails with zero variants set", func(t *testing.T) { + obj := ObjectWithOneOfProperty{ + Variant: &ObjectWithOneOfPropertyVariant{}, + } + _, err := json.Marshal(obj) + assert.Error(t, err) + assert.Contains(t, err.Error(), "exactly one member must be set") + }) + + t.Run("marshal fails with two variants set", func(t *testing.T) { + obj := ObjectWithOneOfProperty{ + Variant: &ObjectWithOneOfPropertyVariant{ + ObjectWithOneOfPropertyVariantOneOf0: &ObjectWithOneOfPropertyVariantOneOf0{ + Kind: ptr("person"), + Name: ptr("Alice"), + }, + ObjectWithOneOfPropertyVariantOneOf1: &ObjectWithOneOfPropertyVariantOneOf1{ + Kind: ptr("counter"), + Count: ptr(10), + }, + }, + } + _, err := json.Marshal(obj) + assert.Error(t, err) + assert.Contains(t, err.Error(), "exactly one member must be set") + }) +} + +// TestAllOfWithOneOf tests marshaling/unmarshaling of allOf containing oneOf +func TestAllOfWithOneOf(t *testing.T) { + t.Run("unmarshal with optionA - ambiguous oneOf errors", func(t *testing.T) { + // The nested oneOf has same ambiguity issue - both variants match + input := `{"base": "test", "optionA": true}` + var obj AllOfWithOneOf + err := json.Unmarshal([]byte(input), &obj) + // The nested AllOfWithOneOfAllOf1 (oneOf) will error due to ambiguity + require.Error(t, err) + assert.Contains(t, err.Error(), "expected exactly one type to match") + }) + + t.Run("unmarshal with optionB - ambiguous oneOf errors", func(t *testing.T) { + input := `{"base": "test", "optionB": 42}` + var obj AllOfWithOneOf + err := json.Unmarshal([]byte(input), &obj) + require.Error(t, err) + assert.Contains(t, err.Error(), "expected exactly one type to match") + }) + + t.Run("marshal with optionA", func(t *testing.T) { + obj := AllOfWithOneOf{ + Base: ptr("test"), + AllOfWithOneOfAllOf1: &AllOfWithOneOfAllOf1{ + AllOfWithOneOfAllOf1OneOf0: &AllOfWithOneOfAllOf1OneOf0{ + OptionA: ptr(true), + }, + }, + } + + data, err := json.Marshal(obj) + require.NoError(t, err) + + // Should contain both base and optionA merged + var m map[string]any + err = json.Unmarshal(data, &m) + require.NoError(t, err) + + assert.Equal(t, "test", m["base"]) + assert.Equal(t, true, m["optionA"]) + }) + + t.Run("marshal with optionB", func(t *testing.T) { + obj := AllOfWithOneOf{ + Base: ptr("test"), + AllOfWithOneOfAllOf1: &AllOfWithOneOfAllOf1{ + AllOfWithOneOfAllOf1OneOf1: &AllOfWithOneOfAllOf1OneOf1{ + OptionB: ptr(42), + }, + }, + } + + data, err := json.Marshal(obj) + require.NoError(t, err) + + var m map[string]any + err = json.Unmarshal(data, &m) + require.NoError(t, err) + + assert.Equal(t, "test", m["base"]) + assert.Equal(t, float64(42), m["optionB"]) // JSON numbers are float64 + }) + + t.Run("marshal with nil union", func(t *testing.T) { + obj := AllOfWithOneOf{ + Base: ptr("only-base"), + } + + data, err := json.Marshal(obj) + require.NoError(t, err) + + var m map[string]any + err = json.Unmarshal(data, &m) + require.NoError(t, err) + + assert.Equal(t, "only-base", m["base"]) + assert.NotContains(t, m, "optionA") + assert.NotContains(t, m, "optionB") + }) +} diff --git a/experimental/internal/codegen/typegen.go b/experimental/internal/codegen/typegen.go new file mode 100644 index 0000000000..e27424bff0 --- /dev/null +++ b/experimental/internal/codegen/typegen.go @@ -0,0 +1,918 @@ +package codegen + +import ( + "fmt" + "sort" + "strings" + + "github.com/pb33f/libopenapi/datamodel/high/base" +) + +// TypeGenerator converts OpenAPI schemas to Go type expressions. +// It tracks required imports and handles recursive type references. +type TypeGenerator struct { + typeMapping TypeMapping + converter *NameConverter + importResolver *ImportResolver + tagGenerator *StructTagGenerator + imports map[string]string // path -> alias (empty string = no alias) + + // schemaIndex maps JSON pointer refs to their descriptors + schemaIndex map[string]*SchemaDescriptor + + // requiredTemplates tracks which custom type templates are needed + requiredTemplates map[string]bool +} + +// NewTypeGenerator creates a TypeGenerator with the given configuration. +func NewTypeGenerator(typeMapping TypeMapping, converter *NameConverter, importResolver *ImportResolver, tagGenerator *StructTagGenerator) *TypeGenerator { + return &TypeGenerator{ + typeMapping: typeMapping, + converter: converter, + importResolver: importResolver, + tagGenerator: tagGenerator, + imports: make(map[string]string), + schemaIndex: make(map[string]*SchemaDescriptor), + requiredTemplates: make(map[string]bool), + } +} + +// IndexSchemas builds a lookup table from JSON pointer to schema descriptor. +// This is called before generation to enable $ref resolution. +func (g *TypeGenerator) IndexSchemas(schemas []*SchemaDescriptor) { + for _, s := range schemas { + ref := s.Path.String() + g.schemaIndex[ref] = s + } +} + +// AddImport records an import path needed by the generated code. +func (g *TypeGenerator) AddImport(path string) { + if path != "" { + g.imports[path] = "" + } +} + +// AddImportAlias records an import path with an alias. +func (g *TypeGenerator) AddImportAlias(path, alias string) { + if path != "" { + g.imports[path] = alias + } +} + +// AddJSONImport adds encoding/json import (used by marshal/unmarshal code). +func (g *TypeGenerator) AddJSONImport() { + g.AddImport("encoding/json") +} + +// AddJSONImports adds encoding/json and fmt imports (used by oneOf marshal/unmarshal code). +func (g *TypeGenerator) AddJSONImports() { + g.AddImport("encoding/json") + g.AddImport("fmt") +} + +// AddNullableTemplate adds the nullable type template to the output. +func (g *TypeGenerator) AddNullableTemplate() { + g.addTemplate("nullable") +} + +// Imports returns the collected imports as a map[path]alias. +func (g *TypeGenerator) Imports() map[string]string { + return g.imports +} + +// RequiredTemplates returns the set of template names needed for custom types. +func (g *TypeGenerator) RequiredTemplates() map[string]bool { + return g.requiredTemplates +} + +// addTemplate records that a custom type template is needed. +func (g *TypeGenerator) addTemplate(templateName string) { + if templateName != "" { + g.requiredTemplates[templateName] = true + } +} + +// GoTypeExpr returns the Go type expression for a schema descriptor. +// This handles references by looking up the target schema's name, +// and inline schemas by generating the appropriate Go type. +func (g *TypeGenerator) GoTypeExpr(desc *SchemaDescriptor) string { + // Handle $ref - return the referenced type's name + if desc.IsReference() { + // Check for external reference first + if desc.IsExternalReference() { + return g.externalRefType(desc) + } + + // Internal reference - look up in schema index + if target, ok := g.schemaIndex[desc.Ref]; ok { + return target.ShortName + } + // Fallback for unresolved references + return "any" + } + + return g.goTypeForSchema(desc.Schema, desc) +} + +// externalRefType resolves an external reference to a qualified Go type. +// Returns "any" if the external ref cannot be resolved. +func (g *TypeGenerator) externalRefType(desc *SchemaDescriptor) string { + filePath, internalPath := desc.ParseExternalRef() + if filePath == "" { + return "any" + } + + // Look up import mapping + if g.importResolver == nil { + // No import resolver configured - can't resolve external refs + return "any" + } + + imp := g.importResolver.Resolve(filePath) + if imp == nil { + // External file not in import mapping + return "any" + } + + // Extract type name from internal path (e.g., #/components/schemas/Pet -> Pet) + typeName := extractTypeNameFromRef(internalPath, g.converter) + if typeName == "" { + return "any" + } + + // If alias is empty, it's the current package (marked with "-") + if imp.Alias == "" { + return typeName + } + + // Add the import + g.AddImportAlias(imp.Path, imp.Alias) + + // Return qualified type + return imp.Alias + "." + typeName +} + +// extractTypeNameFromRef extracts a Go type name from an internal ref path. +// e.g., "#/components/schemas/Pet" -> "Pet" +func extractTypeNameFromRef(ref string, converter *NameConverter) string { + // Remove leading #/ + ref = strings.TrimPrefix(ref, "#/") + parts := strings.Split(ref, "/") + + if len(parts) < 3 { + return "" + } + + // For #/components/schemas/TypeName, the type name is the last part + // We assume external refs point to component schemas + typeName := parts[len(parts)-1] + return converter.ToTypeName(typeName) +} + +// goTypeForSchema generates a Go type expression from an OpenAPI schema. +// The desc parameter provides context (path, parent) for complex types. +func (g *TypeGenerator) goTypeForSchema(schema *base.Schema, desc *SchemaDescriptor) string { + if schema == nil { + return "any" + } + + // Handle composition types + if len(schema.AllOf) > 0 { + return g.allOfType(desc) + } + if len(schema.AnyOf) > 0 { + return g.anyOfType(desc) + } + if len(schema.OneOf) > 0 { + return g.oneOfType(desc) + } + + // Get the primary type from the type array + // OpenAPI 3.1 allows type to be an array like ["string", "null"] + primaryType := getPrimaryType(schema) + + // Check if this is a nullable primitive - wrap in Nullable[T] + nullable := isNullable(schema) + isPrimitive := primaryType == "string" || primaryType == "integer" || primaryType == "number" || primaryType == "boolean" + + var baseType string + switch primaryType { + case "object": + return g.objectType(schema, desc) + case "array": + return g.arrayType(schema, desc) + case "string": + baseType = g.stringType(schema) + case "integer": + baseType = g.integerType(schema) + case "number": + baseType = g.numberType(schema) + case "boolean": + baseType = g.booleanType(schema) + default: + // Unknown or empty type - could be a free-form object + if schema.Properties != nil && schema.Properties.Len() > 0 { + return g.objectType(schema, desc) + } + return "any" + } + + // Wrap nullable primitives in Nullable[T] + if nullable && isPrimitive { + g.AddNullableTemplate() + return "Nullable[" + baseType + "]" + } + + return baseType +} + +// getPrimaryType extracts the primary (non-null) type from a schema. +// OpenAPI 3.1 supports type arrays like ["string", "null"] for nullable. +func getPrimaryType(schema *base.Schema) string { + if len(schema.Type) == 0 { + return "" + } + for _, t := range schema.Type { + if t != "null" { + return t + } + } + return schema.Type[0] +} + +// objectType generates the Go type for an object schema. +// Simple objects with only additionalProperties become maps. +// Objects with properties become named struct types. +func (g *TypeGenerator) objectType(schema *base.Schema, desc *SchemaDescriptor) string { + hasProperties := schema.Properties != nil && schema.Properties.Len() > 0 + hasAdditionalProps := schema.AdditionalProperties != nil + + // Pure map case: no properties, only additionalProperties + if !hasProperties && hasAdditionalProps { + return g.mapType(schema, desc) + } + + // Empty object (no properties, no additionalProperties) + if !hasProperties && !hasAdditionalProps { + return "map[string]any" + } + + // Struct case: has properties (with or without additionalProperties) + // Return the type name - actual struct definition is generated separately + if desc != nil && desc.ShortName != "" { + return desc.ShortName + } + return "any" +} + +// mapType generates a map[string]T type for additionalProperties schemas. +func (g *TypeGenerator) mapType(schema *base.Schema, desc *SchemaDescriptor) string { + if schema.AdditionalProperties == nil { + return "map[string]any" + } + + // additionalProperties can be a boolean or a schema + // If it's a schema proxy (A), get the value type + if schema.AdditionalProperties.A != nil { + valueSchema := schema.AdditionalProperties.A.Schema() + if valueSchema != nil { + valueType := g.goTypeForSchema(valueSchema, nil) + return "map[string]" + valueType + } + } + + // additionalProperties: true or just present + return "map[string]any" +} + +// arrayType generates a []T type for array schemas. +func (g *TypeGenerator) arrayType(schema *base.Schema, desc *SchemaDescriptor) string { + if schema.Items == nil || schema.Items.A == nil { + return "[]any" + } + + // Check if items is a reference + itemProxy := schema.Items.A + if itemProxy.IsReference() { + ref := itemProxy.GetReference() + // Check for external reference first + if !strings.HasPrefix(ref, "#") && strings.Contains(ref, "#") { + // External reference - use import mapping + tempDesc := &SchemaDescriptor{Ref: ref} + itemType := g.externalRefType(tempDesc) + return "[]" + itemType + } + // Internal reference - look up in schema index + if target, ok := g.schemaIndex[ref]; ok { + return "[]" + target.ShortName + } + } + + // Check if we have a descriptor for the items schema + if desc != nil && desc.Items != nil && desc.Items.ShortName != "" { + return "[]" + desc.Items.ShortName + } + + // Inline items schema + itemSchema := itemProxy.Schema() + itemType := g.goTypeForSchema(itemSchema, nil) + return "[]" + itemType +} + +// stringType returns the Go type for a string schema. +func (g *TypeGenerator) stringType(schema *base.Schema) string { + spec := g.typeMapping.String.Default + if schema.Format != "" { + if formatSpec, ok := g.typeMapping.String.Formats[schema.Format]; ok { + spec = formatSpec + } + } + + g.AddImport(spec.Import) + g.addTemplate(spec.Template) + return spec.Type +} + +// integerType returns the Go type for an integer schema. +func (g *TypeGenerator) integerType(schema *base.Schema) string { + spec := g.typeMapping.Integer.Default + if schema.Format != "" { + if formatSpec, ok := g.typeMapping.Integer.Formats[schema.Format]; ok { + spec = formatSpec + } + } + + g.AddImport(spec.Import) + return spec.Type +} + +// numberType returns the Go type for a number schema. +func (g *TypeGenerator) numberType(schema *base.Schema) string { + spec := g.typeMapping.Number.Default + if schema.Format != "" { + if formatSpec, ok := g.typeMapping.Number.Formats[schema.Format]; ok { + spec = formatSpec + } + } + + g.AddImport(spec.Import) + return spec.Type +} + +// booleanType returns the Go type for a boolean schema. +func (g *TypeGenerator) booleanType(schema *base.Schema) string { + spec := g.typeMapping.Boolean.Default + g.AddImport(spec.Import) + return spec.Type +} + +// allOfType returns the type name for an allOf composition. +// allOf is typically used for struct embedding/inheritance. +func (g *TypeGenerator) allOfType(desc *SchemaDescriptor) string { + if desc != nil && desc.ShortName != "" { + return desc.ShortName + } + return "any" +} + +// anyOfType returns the type name for an anyOf composition. +func (g *TypeGenerator) anyOfType(desc *SchemaDescriptor) string { + if desc != nil && desc.ShortName != "" { + return desc.ShortName + } + return "any" +} + +// oneOfType returns the type name for a oneOf composition. +func (g *TypeGenerator) oneOfType(desc *SchemaDescriptor) string { + if desc != nil && desc.ShortName != "" { + return desc.ShortName + } + return "any" +} + +// StructField represents a field in a generated Go struct. +type StructField struct { + Name string // Go field name + Type string // Go type expression + JSONName string // Original JSON property name + Required bool // Is this field required in the schema + Nullable bool // Is this field nullable (type includes "null") + Pointer bool // Should this be a pointer type + OmitEmpty bool // Include omitempty in json tag + OmitZero bool // Include omitzero in json tag (Go 1.24+) + JSONIgnore bool // Use json:"-" tag to exclude from marshaling + Doc string // Field documentation + Default string // Go literal for default value (empty if no default) + IsStruct bool // True if this field is a struct type (for recursive ApplyDefaults) + IsNullableAlias bool // True if type is a type alias to Nullable[T] (don't wrap or pointer) + Order *int // Optional field ordering (lower values come first) +} + +// GenerateStructFields creates the list of struct fields for an object schema. +func (g *TypeGenerator) GenerateStructFields(desc *SchemaDescriptor) []StructField { + schema := desc.Schema + if schema == nil || schema.Properties == nil { + return nil + } + + // Build required set + required := make(map[string]bool) + for _, r := range schema.Required { + required[r] = true + } + + var fields []StructField + needsNullableImport := false + + for pair := schema.Properties.First(); pair != nil; pair = pair.Next() { + propName := pair.Key() + propProxy := pair.Value() + + field := StructField{ + Name: g.converter.ToPropertyName(propName), + JSONName: propName, + Required: required[propName], + } + + // Parse extensions from the property schema + var propExtensions *Extensions + var propSchema *base.Schema + + // Resolve the property schema + var propType string + if propProxy.IsReference() { + ref := propProxy.GetReference() + // Check if this is an external reference + if !strings.HasPrefix(ref, "#") && strings.Contains(ref, "#") { + // External reference - use import mapping + tempDesc := &SchemaDescriptor{Ref: ref} + propType = g.externalRefType(tempDesc) + field.IsStruct = true // external references are typically to struct types + } else if target, ok := g.schemaIndex[ref]; ok { + propType = target.ShortName + // Only set IsStruct if the referenced schema has ApplyDefaults + // This filters out array/map type aliases which don't have ApplyDefaults + field.IsStruct = schemaHasApplyDefaults(target.Schema) + // Check if the referenced schema is nullable + // BUT: if it's a nullable primitive, the type alias already wraps Nullable[T], + // so we shouldn't double-wrap it or add a pointer (Nullable handles "unspecified") + if isNullablePrimitive(target.Schema) { + // Already Nullable[T] - use as value type directly + field.IsNullableAlias = true + } else if isNullable(target.Schema) { + field.Nullable = true + } + // Extensions from referenced schema apply to the field + propExtensions = target.Extensions + } else { + propType = "any" + } + } else { + propSchema = propProxy.Schema() + field.Nullable = isNullable(propSchema) + field.Doc = extractDescription(propSchema) + + // Parse extensions from the property schema + if propSchema != nil && propSchema.Extensions != nil { + ext, err := ParseExtensions(propSchema.Extensions, desc.Path.Append("properties", propName).String()) + if err == nil { + propExtensions = ext + } + } + + // Generate the Go type for this property + // Always use goTypeForSchema to get the correct type expression + // This handles arrays, maps, and primitive types correctly + propType = g.goTypeForSchema(propSchema, desc.Properties[propName]) + + // Check if this is a struct type (object with properties, or a named type) + if propSchema != nil { + if propSchema.Properties != nil && propSchema.Properties.Len() > 0 { + field.IsStruct = true + } + // Extract default value + if propSchema.Default != nil { + field.Default = formatDefaultValue(propSchema.Default.Value, propType) + } + } + } + + // Apply extensions to the field + if propExtensions != nil { + // Name override + if propExtensions.NameOverride != "" { + field.Name = propExtensions.NameOverride + } + + // Type override replaces the generated type entirely + if propExtensions.TypeOverride != nil { + propType = propExtensions.TypeOverride.TypeName + if propExtensions.TypeOverride.ImportPath != "" { + if propExtensions.TypeOverride.ImportAlias != "" { + g.AddImportAlias(propExtensions.TypeOverride.ImportPath, propExtensions.TypeOverride.ImportAlias) + } else { + g.AddImport(propExtensions.TypeOverride.ImportPath) + } + } + // Type override bypasses nullable wrapping - the user specifies the exact type + field.IsNullableAlias = true // Don't wrap or add pointer + } + + // JSON ignore + if propExtensions.JSONIgnore != nil && *propExtensions.JSONIgnore { + field.JSONIgnore = true + } + + // Deprecated reason appended to documentation + if propExtensions.DeprecatedReason != "" { + if field.Doc != "" { + field.Doc = field.Doc + "\nDeprecated: " + propExtensions.DeprecatedReason + } else { + field.Doc = "Deprecated: " + propExtensions.DeprecatedReason + } + } + + // Order for field sorting + if propExtensions.Order != nil { + field.Order = propExtensions.Order + } + } + + // Determine type semantics: + // - Nullable fields: use Nullable[T] + // - Optional (not nullable) fields: use *T (pointer) + // - Required (not nullable) fields: use T (value type) + // - Collections (slices/maps) are never wrapped + // - Types already wrapped in Nullable[] are not double-wrapped + // - Type aliases to Nullable[T] are used as-is (IsNullableAlias) + isCollection := strings.HasPrefix(propType, "[]") || strings.HasPrefix(propType, "map[") + alreadyNullable := strings.HasPrefix(propType, "Nullable[") || field.IsNullableAlias + + if field.Nullable && !isCollection && !alreadyNullable { + // Use Nullable[T] for nullable fields (generated inline from template) + field.Type = "Nullable[" + propType + "]" + field.Pointer = false + needsNullableImport = true + } else if !field.Required && !isCollection && !alreadyNullable { + // Check for skip optional pointer extension + skipPointer := false + if propExtensions != nil && propExtensions.SkipOptionalPointer != nil && *propExtensions.SkipOptionalPointer { + skipPointer = true + } + + if skipPointer { + // Use value type even though optional + field.Type = propType + field.Pointer = false + } else { + // Use pointer for optional non-nullable fields + field.Type = "*" + propType + field.Pointer = true + } + } else { + // Value type for required non-nullable fields, collections, and Nullable aliases + field.Type = propType + field.Pointer = false + } + + // Determine omitempty/omitzero behavior + field.OmitEmpty = !field.Required + if propExtensions != nil { + // Explicit omitempty override + if propExtensions.OmitEmpty != nil { + field.OmitEmpty = *propExtensions.OmitEmpty + } + // Explicit omitzero + if propExtensions.OmitZero != nil && *propExtensions.OmitZero { + field.OmitZero = true + } + } + + fields = append(fields, field) + } + + if needsNullableImport { + g.AddNullableTemplate() + } + + // Sort fields by order if any have explicit ordering + sortFieldsByOrder(fields) + + return fields +} + +// collectFieldsRecursive returns the struct fields for a schema, recursively +// following allOf chains. For schemas with direct properties (no allOf), this +// falls through to GenerateStructFields. For allOf-composed schemas, it +// collects fields from all allOf members recursively, so that nested allOf +// references (e.g., A: allOf[$ref:B, ...] where B: allOf[$ref:C, ...]) are +// properly flattened. +func (g *TypeGenerator) collectFieldsRecursive(desc *SchemaDescriptor) []StructField { + schema := desc.Schema + if schema == nil { + return nil + } + + // If this schema has no allOf, use the standard field generation + if len(schema.AllOf) == 0 { + return g.GenerateStructFields(desc) + } + + // Collect fields from direct properties first + var fields []StructField + if schema.Properties != nil && schema.Properties.Len() > 0 { + fields = append(fields, g.GenerateStructFields(desc)...) + } + + // Recursively collect fields from each allOf member + for i, proxy := range schema.AllOf { + memberSchema := proxy.Schema() + if memberSchema == nil { + continue + } + + var memberFields []StructField + if proxy.IsReference() { + ref := proxy.GetReference() + if target, ok := g.schemaIndex[ref]; ok { + // Recurse: the target may itself be an allOf composition + memberFields = g.collectFieldsRecursive(target) + } + } else if memberSchema.Properties != nil && memberSchema.Properties.Len() > 0 { + if desc.AllOf != nil && i < len(desc.AllOf) { + memberFields = g.GenerateStructFields(desc.AllOf[i]) + } + } + + // Apply required array from this allOf member to collected fields + if len(memberSchema.Required) > 0 { + reqSet := make(map[string]bool) + for _, r := range memberSchema.Required { + reqSet[r] = true + } + for j := range memberFields { + if reqSet[memberFields[j].JSONName] && !memberFields[j].Required { + memberFields[j].Required = true + memberFields[j].OmitEmpty = false + if !memberFields[j].Nullable && !strings.HasPrefix(memberFields[j].Type, "[]") && !strings.HasPrefix(memberFields[j].Type, "map[") { + memberFields[j].Type = strings.TrimPrefix(memberFields[j].Type, "*") + memberFields[j].Pointer = false + } + } + } + } + + fields = append(fields, memberFields...) + } + + return fields +} + +// isNullable checks if a schema allows null values. +// In OpenAPI 3.1, this is expressed as type: ["string", "null"] +// In OpenAPI 3.0, this is expressed as nullable: true +func isNullable(schema *base.Schema) bool { + if schema == nil { + return false + } + + // OpenAPI 3.1 style: type array includes "null" + for _, t := range schema.Type { + if t == "null" { + return true + } + } + + // OpenAPI 3.0 style: nullable: true + if schema.Nullable != nil && *schema.Nullable { + return true + } + + return false +} + +// extractDescription gets the description from a schema. +func extractDescription(schema *base.Schema) string { + if schema == nil { + return "" + } + return schema.Description +} + +// formatDefaultValue converts an OpenAPI default value to a Go literal. +// goType is used to determine the correct format for the literal. +func formatDefaultValue(value any, goType string) string { + if value == nil { + return "" + } + + // Strip pointer prefix for type matching + baseType := strings.TrimPrefix(goType, "*") + + switch v := value.(type) { + case string: + // Check if the target type is not a string + // YAML/JSON might parse "10" or "true" as strings + switch baseType { + case "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64": + // Return the string as-is if it looks like a number + return v + case "bool": + // Return the string as-is if it looks like a bool + if v == "true" || v == "false" { + return v + } + case "float32", "float64": + return v + } + // It's actually a string type - quote it + return fmt.Sprintf("%q", v) + case bool: + return fmt.Sprintf("%t", v) + case float64: + // JSON numbers are always float64 + // Check if it's actually an integer + if v == float64(int64(v)) { + // It's a whole number + if strings.HasPrefix(baseType, "int") || strings.HasPrefix(baseType, "uint") { + return fmt.Sprintf("%d", int64(v)) + } + } + return fmt.Sprintf("%v", v) + case int, int64: + return fmt.Sprintf("%d", v) + case []any: + // Arrays - generate a slice literal + // For now, return empty slice if complex + if len(v) == 0 { + return fmt.Sprintf("%s{}", goType) + } + // Complex array defaults would need recursive handling + return "" + case map[string]any: + // Objects - for now, skip complex defaults + if len(v) == 0 { + return fmt.Sprintf("%s{}", goType) + } + return "" + default: + // Try a simple string conversion + return fmt.Sprintf("%v", v) + } +} + +// HasAdditionalProperties returns true if the schema has explicit additionalProperties. +func (g *TypeGenerator) HasAdditionalProperties(desc *SchemaDescriptor) bool { + if desc == nil || desc.Schema == nil { + return false + } + return desc.Schema.AdditionalProperties != nil +} + +// AdditionalPropertiesType returns the Go type for the additionalProperties. +func (g *TypeGenerator) AdditionalPropertiesType(desc *SchemaDescriptor) string { + if desc == nil || desc.Schema == nil || desc.Schema.AdditionalProperties == nil { + return "any" + } + + if desc.Schema.AdditionalProperties.A != nil { + valueSchema := desc.Schema.AdditionalProperties.A.Schema() + if valueSchema != nil { + return g.goTypeForSchema(valueSchema, nil) + } + } + + return "any" +} + +// SchemaKind represents the kind of schema for code generation. +type SchemaKind int + +const ( + KindStruct SchemaKind = iota + KindMap + KindAlias + KindEnum + KindAllOf + KindAnyOf + KindOneOf + KindReference +) + +// GetSchemaKind determines what kind of Go type to generate for a schema. +func GetSchemaKind(desc *SchemaDescriptor) SchemaKind { + if desc.IsReference() { + return KindReference + } + + schema := desc.Schema + if schema == nil { + return KindAlias + } + + // Enum check first + if len(schema.Enum) > 0 { + return KindEnum + } + + // Composition types + if len(schema.AllOf) > 0 { + return KindAllOf + } + if len(schema.AnyOf) > 0 { + return KindAnyOf + } + if len(schema.OneOf) > 0 { + return KindOneOf + } + + // Object with properties -> struct + if schema.Properties != nil && schema.Properties.Len() > 0 { + return KindStruct + } + + // Object with only additionalProperties -> map + primaryType := getPrimaryType(schema) + if primaryType == "object" { + if schema.AdditionalProperties != nil { + return KindMap + } + return KindStruct // empty struct + } + + // Everything else is an alias to a primitive type + return KindAlias +} + +// FormatJSONTag generates a JSON struct tag for a field. +// Deprecated: Use StructTagGenerator instead. +func FormatJSONTag(jsonName string, omitEmpty bool) string { + if omitEmpty { + return fmt.Sprintf("`json:\"%s,omitempty\"`", jsonName) + } + return fmt.Sprintf("`json:\"%s\"`", jsonName) +} + +// GenerateFieldTag generates struct tags for a field using the configured templates. +func (g *TypeGenerator) GenerateFieldTag(field StructField) string { + if g.tagGenerator == nil { + // Fallback to legacy behavior + if field.JSONIgnore { + return "`json:\"-\"`" + } + return FormatJSONTag(field.JSONName, field.OmitEmpty) + } + + info := StructTagInfo{ + FieldName: field.JSONName, + GoFieldName: field.Name, + IsOptional: !field.Required, + IsNullable: field.Nullable, + IsPointer: field.Pointer, + OmitEmpty: field.OmitEmpty, + OmitZero: field.OmitZero, + JSONIgnore: field.JSONIgnore, + } + return g.tagGenerator.GenerateTags(info) +} + +// TagGenerator returns the struct tag generator. +func (g *TypeGenerator) TagGenerator() *StructTagGenerator { + return g.tagGenerator +} + +// sortFieldsByOrder sorts fields by their Order value. +// Fields without an Order value are placed after fields with explicit ordering, +// maintaining their original relative order (stable sort). +func sortFieldsByOrder(fields []StructField) { + // Check if any fields have explicit ordering + hasOrder := false + for _, f := range fields { + if f.Order != nil { + hasOrder = true + break + } + } + if !hasOrder { + return + } + + // Stable sort to preserve relative order of fields without explicit ordering + sort.SliceStable(fields, func(i, j int) bool { + // Fields with Order come before fields without + if fields[i].Order == nil && fields[j].Order == nil { + return false // preserve original order + } + if fields[i].Order == nil { + return false // i (no order) comes after j + } + if fields[j].Order == nil { + return true // i (has order) comes before j + } + // Both have order - sort by value + return *fields[i].Order < *fields[j].Order + }) +} diff --git a/experimental/internal/codegen/typemapping.go b/experimental/internal/codegen/typemapping.go new file mode 100644 index 0000000000..235b06260f --- /dev/null +++ b/experimental/internal/codegen/typemapping.go @@ -0,0 +1,98 @@ +package codegen + +// SimpleTypeSpec is used to define the Go typename of a simple type like +// an int or a string, along with the import required to use it. +type SimpleTypeSpec struct { + Type string `yaml:"type"` + Import string `yaml:"import,omitempty"` + Template string `yaml:"template,omitempty"` +} + +// FormatMapping defines the default Go type and format-specific overrides. +type FormatMapping struct { + Default SimpleTypeSpec `yaml:"default"` + Formats map[string]SimpleTypeSpec `yaml:"formats,omitempty"` +} + +// TypeMapping defines the mapping from OpenAPI types to Go types. +type TypeMapping struct { + Integer FormatMapping `yaml:"integer,omitempty"` + Number FormatMapping `yaml:"number,omitempty"` + Boolean FormatMapping `yaml:"boolean,omitempty"` + String FormatMapping `yaml:"string,omitempty"` +} + +// 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 + for k, v := range base.Formats { + result.Formats[k] = v + } + + // Override with user default if specified + if user.Default.Type != "" { + result.Default = user.Default + } + + // Override/add user formats + for k, v := range user.Formats { + result.Formats[k] = v + } + + return result +} + +// 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: "Email", Template: "email.tmpl"}, + "date": {Type: "Date", Template: "date.tmpl"}, + "date-time": {Type: "time.Time", Import: "time"}, + "json": {Type: "json.RawMessage", Import: "encoding/json"}, + "uuid": {Type: "UUID", Template: "uuid.tmpl"}, + "binary": {Type: "File", Template: "file.tmpl"}, + }, + }, +} diff --git a/experimental/internal/codegen/typenames.go b/experimental/internal/codegen/typenames.go new file mode 100644 index 0000000000..c4d47b51af --- /dev/null +++ b/experimental/internal/codegen/typenames.go @@ -0,0 +1 @@ +package codegen diff --git a/scripts/foreach-module.sh b/scripts/foreach-module.sh new file mode 100755 index 0000000000..7addae7825 --- /dev/null +++ b/scripts/foreach-module.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Run a make target in each child go module whose go directive is compatible +# with the current Go toolchain. Modules requiring a newer Go are skipped. +# +# Usage: foreach-module.sh +set -euo pipefail + +target="${1:?usage: foreach-module.sh }" +cur_go="$(go env GOVERSION | sed 's/^go//')" + +git ls-files '**/*go.mod' -z | while IFS= read -r -d '' modfile; do + mod_go="$(sed -n 's/^go *//p' "$modfile")" + moddir="$(dirname "$modfile")" + + if [ "$(printf '%s\n%s' "$mod_go" "$cur_go" | sort -V | head -1)" = "$mod_go" ]; then + (set -x; cd "$moddir" && env GOBIN="${GOBIN:-}" make "$target") + else + echo "Skipping $moddir: requires go $mod_go, have go $cur_go" + fi +done From 98e5d1a848441a135ed4addd4934329b2309e81f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:20:16 -0800 Subject: [PATCH 150/293] fix(deps): update module github.com/go-chi/chi/v5 to v5.2.2 [security] (#2198) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- experimental/examples/petstore-expanded/chi/go.mod | 2 +- experimental/examples/petstore-expanded/chi/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/examples/petstore-expanded/chi/go.mod b/experimental/examples/petstore-expanded/chi/go.mod index 3c9d10741e..58fa2448db 100644 --- a/experimental/examples/petstore-expanded/chi/go.mod +++ b/experimental/examples/petstore-expanded/chi/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expan go 1.24.0 require ( - github.com/go-chi/chi/v5 v5.2.0 + github.com/go-chi/chi/v5 v5.2.2 github.com/google/uuid v1.6.0 github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 ) diff --git a/experimental/examples/petstore-expanded/chi/go.sum b/experimental/examples/petstore-expanded/chi/go.sum index ad495c8907..54ce010d7c 100644 --- a/experimental/examples/petstore-expanded/chi/go.sum +++ b/experimental/examples/petstore-expanded/chi/go.sum @@ -1,4 +1,4 @@ -github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= -github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= 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= From db8abb866c5b99d169290020eb23416c3c5c79fc Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 6 Feb 2026 21:19:06 -0800 Subject: [PATCH 151/293] Add output filtering (#2201) * Add output filtering Fixes #2200 Add output filtering like in V2, and support fetching specs via HTTP. * Fix lint issue --------- Co-authored-by: Marcin Romaszewicz --- experimental/Configuration.md | 20 ++ experimental/cmd/oapi-codegen/main.go | 46 ++- experimental/internal/codegen/codegen.go | 9 + .../internal/codegen/configuration.go | 16 + experimental/internal/codegen/filter.go | 97 ++++++ experimental/internal/codegen/filter_test.go | 323 ++++++++++++++++++ 6 files changed, 506 insertions(+), 5 deletions(-) create mode 100644 experimental/internal/codegen/filter.go create mode 100644 experimental/internal/codegen/filter_test.go diff --git a/experimental/Configuration.md b/experimental/Configuration.md index 55f550e2f3..db2d3ed508 100644 --- a/experimental/Configuration.md +++ b/experimental/Configuration.md @@ -37,6 +37,26 @@ generation: path: github.com/org/project/models alias: models # optional, defaults to last segment of path +# Output options: control which operations and schemas are included. +output-options: + # Only include operations tagged with one of these tags. Ignored when empty. + include-tags: + - public + - beta + # Exclude operations tagged with one of these tags. Ignored when empty. + exclude-tags: + - internal + # Only include operations with one of these operation IDs. Ignored when empty. + include-operation-ids: + - listPets + - createPet + # Exclude operations with one of these operation IDs. Ignored when empty. + exclude-operation-ids: + - deprecatedEndpoint + # Exclude schemas with the given names from generation. Ignored when empty. + exclude-schemas: + - InternalConfig + # Type mappings: OpenAPI type/format to Go type. # User values are merged on top of defaults — you only need to specify overrides. type-mapping: diff --git a/experimental/cmd/oapi-codegen/main.go b/experimental/cmd/oapi-codegen/main.go index 24c5320c90..50205e846c 100644 --- a/experimental/cmd/oapi-codegen/main.go +++ b/experimental/cmd/oapi-codegen/main.go @@ -3,6 +3,9 @@ package main import ( "flag" "fmt" + "io" + "net/http" + "net/url" "os" "path/filepath" "strings" @@ -20,9 +23,9 @@ func main() { flagPackage := flag.String("package", "", "Go package name for generated code") flagOutput := flag.String("output", "", "output file path (default: .gen.go)") flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Arguments:\n") - fmt.Fprintf(os.Stderr, " spec-path path to OpenAPI spec file\n\n") + fmt.Fprintf(os.Stderr, " spec-path-or-url path or URL to OpenAPI spec file\n\n") fmt.Fprintf(os.Stderr, "Options:\n") flag.PrintDefaults() } @@ -35,8 +38,8 @@ func main() { specPath := flag.Arg(0) - // Parse the OpenAPI spec - specData, err := os.ReadFile(specPath) + // Load the OpenAPI spec from file or URL + specData, err := loadSpec(specPath) if err != nil { fmt.Fprintf(os.Stderr, "error reading spec: %v\n", err) os.Exit(1) @@ -78,7 +81,12 @@ func main() { // Default output to .gen.go if cfg.Output == "" { - base := filepath.Base(specPath) + // For URLs, extract the filename from the URL path + baseName := specPath + if u, err := url.Parse(specPath); err == nil && u.Scheme != "" && u.Host != "" { + baseName = u.Path + } + base := filepath.Base(baseName) ext := filepath.Ext(base) cfg.Output = strings.TrimSuffix(base, ext) + ".gen.go" } @@ -103,3 +111,31 @@ func main() { fmt.Printf("Generated %s\n", cfg.Output) } + +// loadSpec loads an OpenAPI spec from a file path or URL. +func loadSpec(specPath string) ([]byte, error) { + u, err := url.Parse(specPath) + if err == nil && u.Scheme != "" && u.Host != "" { + return loadSpecFromURL(u.String()) + } + return os.ReadFile(specPath) +} + +// loadSpecFromURL fetches an OpenAPI spec from an HTTP(S) URL. +func loadSpecFromURL(specURL string) ([]byte, error) { + resp, err := http.Get(specURL) //nolint:gosec // URL comes from user-provided spec path + if err != nil { + return nil, fmt.Errorf("fetching spec from URL: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("fetching spec from URL: HTTP %d %s", resp.StatusCode, resp.Status) + } + + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("reading spec from URL: %w", err) + } + return data, nil +} diff --git a/experimental/internal/codegen/codegen.go b/experimental/internal/codegen/codegen.go index 5b6fdff894..7ff2175067 100644 --- a/experimental/internal/codegen/codegen.go +++ b/experimental/internal/codegen/codegen.go @@ -31,6 +31,9 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering schemas: %w", err) } + // Filter excluded schemas + schemas = FilterSchemasByName(schemas, cfg.OutputOptions.ExcludeSchemas) + // Pass 2: Compute names for all schemas converter := NewNameConverter(cfg.NameMangling, cfg.NameSubstitutions) ComputeSchemaNames(schemas, converter, contentTypeNamer) @@ -102,6 +105,9 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering operations: %w", err) } + // Apply operation filters + ops = FilterOperations(ops, cfg.OutputOptions) + // Generate client clientGen, err := NewClientGenerator(schemaIndex, cfg.Generation.SimpleClient, cfg.Generation.ModelsPackage) if err != nil { @@ -158,6 +164,9 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering operations: %w", err) } + // Apply operation filters + ops = FilterOperations(ops, cfg.OutputOptions) + if len(ops) > 0 { // Generate server serverGen, err := NewServerGenerator(cfg.Generation.Server) diff --git a/experimental/internal/codegen/configuration.go b/experimental/internal/codegen/configuration.go index c8d1b87388..0dc128f9ea 100644 --- a/experimental/internal/codegen/configuration.go +++ b/experimental/internal/codegen/configuration.go @@ -15,6 +15,8 @@ type Configuration struct { Output string `yaml:"output"` // Generation controls which parts of the code are generated Generation GenerationOptions `yaml:"generation,omitempty"` + // OutputOptions controls filtering of operations and schemas + OutputOptions OutputOptions `yaml:"output-options,omitempty"` // TypeMapping allows customizing OpenAPI type/format to Go type mappings TypeMapping TypeMapping `yaml:"type-mapping,omitempty"` // NameMangling configures how OpenAPI names are converted to Go identifiers @@ -38,6 +40,20 @@ type Configuration struct { StructTags StructTagsConfig `yaml:"struct-tags,omitempty"` } +// OutputOptions controls filtering of which operations and schemas are included in generation. +type OutputOptions struct { + // IncludeTags only includes operations tagged with one of these tags. Ignored when empty. + IncludeTags []string `yaml:"include-tags,omitempty"` + // ExcludeTags excludes operations tagged with one of these tags. Ignored when empty. + ExcludeTags []string `yaml:"exclude-tags,omitempty"` + // IncludeOperationIDs only includes operations with one of these operation IDs. Ignored when empty. + IncludeOperationIDs []string `yaml:"include-operation-ids,omitempty"` + // ExcludeOperationIDs excludes operations with one of these operation IDs. Ignored when empty. + ExcludeOperationIDs []string `yaml:"exclude-operation-ids,omitempty"` + // ExcludeSchemas excludes schemas with the given names from generation. Ignored when empty. + ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` +} + // ModelsPackage specifies an external package containing the model types. type ModelsPackage struct { // Path is the import path for the models package (e.g., "github.com/org/project/models") diff --git a/experimental/internal/codegen/filter.go b/experimental/internal/codegen/filter.go new file mode 100644 index 0000000000..8e20bed5af --- /dev/null +++ b/experimental/internal/codegen/filter.go @@ -0,0 +1,97 @@ +package codegen + +// FilterOperationsByTag filters operations based on include/exclude tag lists. +// Exclude is applied first, then include. +func FilterOperationsByTag(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { + if len(opts.ExcludeTags) > 0 { + tags := sliceToSet(opts.ExcludeTags) + ops = filterOps(ops, func(op *OperationDescriptor) bool { + return !operationHasTag(op, tags) + }) + } + if len(opts.IncludeTags) > 0 { + tags := sliceToSet(opts.IncludeTags) + ops = filterOps(ops, func(op *OperationDescriptor) bool { + return operationHasTag(op, tags) + }) + } + return ops +} + +// FilterOperationsByOperationID filters operations based on include/exclude operation ID lists. +// Exclude is applied first, then include. +func FilterOperationsByOperationID(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { + if len(opts.ExcludeOperationIDs) > 0 { + ids := sliceToSet(opts.ExcludeOperationIDs) + ops = filterOps(ops, func(op *OperationDescriptor) bool { + return !ids[op.OperationID] + }) + } + if len(opts.IncludeOperationIDs) > 0 { + ids := sliceToSet(opts.IncludeOperationIDs) + ops = filterOps(ops, func(op *OperationDescriptor) bool { + return ids[op.OperationID] + }) + } + return ops +} + +// FilterOperations applies all operation filters (tags, operation IDs) from OutputOptions. +func FilterOperations(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { + ops = FilterOperationsByTag(ops, opts) + ops = FilterOperationsByOperationID(ops, opts) + return ops +} + +// FilterSchemasByName removes schemas whose component name is in the exclude list. +// Only filters top-level component schemas (path: components/schemas/). +func FilterSchemasByName(schemas []*SchemaDescriptor, excludeNames []string) []*SchemaDescriptor { + if len(excludeNames) == 0 { + return schemas + } + excluded := sliceToSet(excludeNames) + result := make([]*SchemaDescriptor, 0, len(schemas)) + for _, s := range schemas { + // Check if this is a top-level component schema + if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { + if excluded[s.Path[2]] { + continue + } + } + result = append(result, s) + } + return result +} + +// operationHasTag returns true if the operation has any of the given tags. +func operationHasTag(op *OperationDescriptor, tags map[string]bool) bool { + if op == nil || op.Spec == nil { + return false + } + for _, tag := range op.Spec.Tags { + if tags[tag] { + return true + } + } + return false +} + +// filterOps returns operations that satisfy the predicate. +func filterOps(ops []*OperationDescriptor, keep func(*OperationDescriptor) bool) []*OperationDescriptor { + result := make([]*OperationDescriptor, 0, len(ops)) + for _, op := range ops { + if keep(op) { + result = append(result, op) + } + } + return result +} + +// sliceToSet converts a string slice to a set (map[string]bool). +func sliceToSet(items []string) map[string]bool { + m := make(map[string]bool, len(items)) + for _, item := range items { + m[item] = true + } + return m +} diff --git a/experimental/internal/codegen/filter_test.go b/experimental/internal/codegen/filter_test.go new file mode 100644 index 0000000000..9e0f960a86 --- /dev/null +++ b/experimental/internal/codegen/filter_test.go @@ -0,0 +1,323 @@ +package codegen + +import ( + "testing" + + "github.com/pb33f/libopenapi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const filterTestSpec = `openapi: "3.1.0" +info: + title: Filter Test API + version: "1.0" +paths: + /users: + get: + operationId: listUsers + tags: + - users + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + /pets: + get: + operationId: listPets + tags: + - pets + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /admin/settings: + get: + operationId: getSettings + tags: + - admin + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Settings' + put: + operationId: updateSettings + tags: + - admin + responses: + "200": + description: OK +components: + schemas: + User: + type: object + properties: + name: + type: string + Pet: + type: object + properties: + name: + type: string + Settings: + type: object + properties: + theme: + type: string +` + +func gatherTestOps(t *testing.T) []*OperationDescriptor { + t.Helper() + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + tracker := NewParamUsageTracker() + ops, err := GatherOperations(doc, tracker) + require.NoError(t, err) + return ops +} + +func opIDs(ops []*OperationDescriptor) []string { + ids := make([]string, len(ops)) + for i, op := range ops { + ids[i] = op.OperationID + } + return ids +} + +func TestFilterOperationsByTag_Include(t *testing.T) { + ops := gatherTestOps(t) + require.Len(t, ops, 4) + + filtered := FilterOperationsByTag(ops, OutputOptions{ + IncludeTags: []string{"users"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "listUsers") + assert.NotContains(t, ids, "listPets") + assert.NotContains(t, ids, "getSettings") + assert.NotContains(t, ids, "updateSettings") +} + +func TestFilterOperationsByTag_Exclude(t *testing.T) { + ops := gatherTestOps(t) + + filtered := FilterOperationsByTag(ops, OutputOptions{ + ExcludeTags: []string{"admin"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "listUsers") + assert.Contains(t, ids, "listPets") + assert.NotContains(t, ids, "getSettings") + assert.NotContains(t, ids, "updateSettings") +} + +func TestFilterOperationsByTag_IncludeMultiple(t *testing.T) { + ops := gatherTestOps(t) + + filtered := FilterOperationsByTag(ops, OutputOptions{ + IncludeTags: []string{"users", "pets"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "listUsers") + assert.Contains(t, ids, "listPets") + assert.NotContains(t, ids, "getSettings") + assert.Len(t, filtered, 2) +} + +func TestFilterOperationsByTag_Empty(t *testing.T) { + ops := gatherTestOps(t) + + filtered := FilterOperationsByTag(ops, OutputOptions{}) + assert.Len(t, filtered, 4) +} + +func TestFilterOperationsByOperationID_Include(t *testing.T) { + ops := gatherTestOps(t) + + filtered := FilterOperationsByOperationID(ops, OutputOptions{ + IncludeOperationIDs: []string{"listPets"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "listPets") + assert.Len(t, filtered, 1) +} + +func TestFilterOperationsByOperationID_Exclude(t *testing.T) { + ops := gatherTestOps(t) + + filtered := FilterOperationsByOperationID(ops, OutputOptions{ + ExcludeOperationIDs: []string{"getSettings", "updateSettings"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "listUsers") + assert.Contains(t, ids, "listPets") + assert.NotContains(t, ids, "getSettings") + assert.NotContains(t, ids, "updateSettings") + assert.Len(t, filtered, 2) +} + +func TestFilterOperations_Combined(t *testing.T) { + ops := gatherTestOps(t) + + // Include only admin, then exclude updateSettings + filtered := FilterOperations(ops, OutputOptions{ + IncludeTags: []string{"admin"}, + ExcludeOperationIDs: []string{"updateSettings"}, + }) + + ids := opIDs(filtered) + assert.Contains(t, ids, "getSettings") + assert.NotContains(t, ids, "updateSettings") + assert.Len(t, filtered, 1) +} + +func TestFilterSchemasByName(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + matcher := NewContentTypeMatcher(DefaultContentTypes()) + schemas, err := GatherSchemas(doc, matcher) + require.NoError(t, err) + + // Count component schemas + var componentNames []string + for _, s := range schemas { + if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { + componentNames = append(componentNames, s.Path[2]) + } + } + assert.Contains(t, componentNames, "User") + assert.Contains(t, componentNames, "Pet") + assert.Contains(t, componentNames, "Settings") + + // Exclude Pet + filtered := FilterSchemasByName(schemas, []string{"Pet"}) + + var filteredNames []string + for _, s := range filtered { + if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { + filteredNames = append(filteredNames, s.Path[2]) + } + } + assert.Contains(t, filteredNames, "User") + assert.NotContains(t, filteredNames, "Pet") + assert.Contains(t, filteredNames, "Settings") +} + +func TestFilterSchemasByName_Empty(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + matcher := NewContentTypeMatcher(DefaultContentTypes()) + schemas, err := GatherSchemas(doc, matcher) + require.NoError(t, err) + + filtered := FilterSchemasByName(schemas, nil) + assert.Equal(t, len(schemas), len(filtered)) +} + +func TestFilterIntegration_GenerateWithIncludeTags(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + Generation: GenerationOptions{ + Client: true, + }, + OutputOptions: OutputOptions{ + IncludeTags: []string{"users"}, + }, + } + + code, err := Generate(doc, []byte(filterTestSpec), cfg) + require.NoError(t, err) + // Client interface should only contain the included operation + assert.Contains(t, code, "ListUsers(ctx context.Context") + assert.NotContains(t, code, "ListPets(ctx context.Context") + assert.NotContains(t, code, "GetSettings(ctx context.Context") +} + +func TestFilterIntegration_GenerateWithExcludeTags(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + Generation: GenerationOptions{ + Client: true, + }, + OutputOptions: OutputOptions{ + ExcludeTags: []string{"admin"}, + }, + } + + code, err := Generate(doc, []byte(filterTestSpec), cfg) + require.NoError(t, err) + // Client interface should include users and pets but not admin operations + assert.Contains(t, code, "ListUsers(ctx context.Context") + assert.Contains(t, code, "ListPets(ctx context.Context") + assert.NotContains(t, code, "GetSettings(ctx context.Context") + assert.NotContains(t, code, "UpdateSettings(ctx context.Context") +} + +func TestFilterIntegration_GenerateWithExcludeSchemas(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + OutputOptions: OutputOptions{ + ExcludeSchemas: []string{"Pet"}, + }, + } + + code, err := Generate(doc, []byte(filterTestSpec), cfg) + require.NoError(t, err) + // User and Settings types should still exist + assert.Contains(t, code, "type User struct") + assert.Contains(t, code, "type Settings struct") + // Pet type should be excluded + assert.NotContains(t, code, "type Pet struct") +} + +func TestFilterIntegration_ServerWithIncludeTags(t *testing.T) { + doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) + require.NoError(t, err) + + cfg := Configuration{ + PackageName: "testpkg", + Generation: GenerationOptions{ + Server: ServerTypeStdHTTP, + }, + OutputOptions: OutputOptions{ + IncludeTags: []string{"pets"}, + }, + } + + code, err := Generate(doc, []byte(filterTestSpec), cfg) + require.NoError(t, err) + // Server interface should only contain the included operation + assert.Contains(t, code, "ListPets(w http.ResponseWriter") + assert.NotContains(t, code, "ListUsers(w http.ResponseWriter") + assert.NotContains(t, code, "GetSettings(w http.ResponseWriter") +} From 17ba42e132420ffe0b67b15fafa4750ab144b1c5 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 7 Feb 2026 00:41:32 -0800 Subject: [PATCH 152/293] Rename Swagger references to OpenAPI (#2202) Co-authored-by: Marcin Romaszewicz --- .../examples/callback/treefarm.gen.go | 22 ++++++++--------- .../petstore-expanded/petstore.gen.go | 22 ++++++++--------- .../examples/webhook/doorbadge.gen.go | 22 ++++++++--------- experimental/internal/codegen/inline.go | 24 +++++++++---------- experimental/internal/codegen/inline_test.go | 18 +++++++------- .../templates/files/client/base.go.tmpl | 2 +- .../comprehensive/output/comprehensive.gen.go | 22 ++++++++--------- .../issues/issue_1029/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1039/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1397/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1429/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1496/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1710/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_193/output/types.gen.go | 22 ++++++++--------- .../issues/issue_2102/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_312/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_502/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_52/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_579/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_697/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_775/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_832/output/types.gen.go | 22 ++++++++--------- .../output/types.gen.go | 22 ++++++++--------- .../output/types.gen.go | 22 ++++++++--------- .../output/nested_aggregate.gen.go | 22 ++++++++--------- 25 files changed, 264 insertions(+), 264 deletions(-) diff --git a/experimental/examples/callback/treefarm.gen.go b/experimental/examples/callback/treefarm.gen.go index a1018c08e9..6d74b06f80 100644 --- a/experimental/examples/callback/treefarm.gen.go +++ b/experimental/examples/callback/treefarm.gen.go @@ -80,7 +80,7 @@ func (s *Error) ApplyDefaults() { type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/8RXwW7bOBC96ysGaQG3QCO76U23bJEFAhSbIHGQ44IWxxYbilTJUbzG7gL7EfuF+yUL", "khJFy4rr9NKcopDzZvhm5s1EN6hYIwo4+5R/zBdnmVBrXWQAz2is0KqAj/kiX2QAJEhiAUuDCL8yU2cA", "HG1pREP+3l8ZAMAlkLvQSKZIqA1YNM+iRKCKEXCstbJkGKGFmwbV5e01lEzKFSufbO4BlhVCKQUqAtuu", @@ -103,9 +103,9 @@ var swaggerSpecJSON = []string{ "36d8LLPs/wAAAP//y9dX5mEQAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -122,24 +122,24 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } // ServerInterface represents all server handlers. diff --git a/experimental/examples/petstore-expanded/petstore.gen.go b/experimental/examples/petstore-expanded/petstore.gen.go index 4149df2b00..c958265c74 100644 --- a/experimental/examples/petstore-expanded/petstore.gen.go +++ b/experimental/examples/petstore-expanded/petstore.gen.go @@ -46,7 +46,7 @@ func (s *Error) ApplyDefaults() { type FindPetsJSONResponse = []Pet // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/+xXXW9byQ19168gtgXyoly5yaIPemo2TgED3cStd/tOz6UkLubLQ44coe1/Lzj3Srqy", "ZG+CYvuF9YMNz3A4hzyHHN6UKWLmJXzztrvqrr6ZcVyl5QxgS0U4xSX8ztZnAMrqaQl3j7heU4FbUtFU", "aAbQk7jCWZv5OxAM2RO8u70B3aBCFRJAyOMBQAGMQJ8HM03QU0hRtKASrAi1FhLgCLoh+JQpmqe33RVI", @@ -77,9 +77,9 @@ var swaggerSpecJSON = []string{ "5gbvFMOI4GujHzzt4f8zAAD//6ZcwVZEFgAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -96,22 +96,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/examples/webhook/doorbadge.gen.go b/experimental/examples/webhook/doorbadge.gen.go index 702d74db62..b51b7d405f 100644 --- a/experimental/examples/webhook/doorbadge.gen.go +++ b/experimental/examples/webhook/doorbadge.gen.go @@ -72,7 +72,7 @@ const ( type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/9RWTY/bNhC961cM0gI+RfLu9qTbJuvDAkGycFL0TItjaxKJZIaUvEbb/16Q1GdX3l0D", "RZv6ZEnDmfceh4+jDSphKIc3N+lVun6TkNrrPAFokS1plcNVuk7XCYAjV2EOd1ozvBPygLBFIZETAIm2", "YDIuxP+RAADcgvSBuxDIIRAscksFgiuFA4m1VtaxcGjhk0F1+3APN+kVHHFXav3NpiHP+4pQOQuMB7IO", @@ -91,9 +91,9 @@ var swaggerSpecJSON = []string{ "xUw9/L8CAAD//+XREy3yDQAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -110,24 +110,24 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } // ServerInterface represents all server handlers. diff --git a/experimental/internal/codegen/inline.go b/experimental/internal/codegen/inline.go index 25767cffa8..1a9554f73e 100644 --- a/experimental/internal/codegen/inline.go +++ b/experimental/internal/codegen/inline.go @@ -9,7 +9,7 @@ import ( ) // generateEmbeddedSpec produces Go code that embeds the raw OpenAPI spec as -// gzip+base64 encoded data, with a public GetSwaggerSpecJSON() function to +// gzip+base64 encoded data, with a public GetOpenAPISpecJSON() function to // retrieve the decompressed JSON bytes. func generateEmbeddedSpec(specData []byte) (string, error) { // Gzip compress @@ -43,15 +43,15 @@ func generateEmbeddedSpec(specData []byte) (string, error) { var b strings.Builder b.WriteString("// Base64-encoded, gzip-compressed OpenAPI spec.\n") - b.WriteString("var swaggerSpecJSON = []string{\n") + b.WriteString("var openAPISpecJSON = []string{\n") for _, chunk := range chunks { fmt.Fprintf(&b, "\t%q,\n", chunk) } b.WriteString("}\n\n") - b.WriteString("// decodeSwaggerSpec decodes and decompresses the embedded spec.\n") - b.WriteString("func decodeSwaggerSpec() ([]byte, error) {\n") - b.WriteString("\tjoined := strings.Join(swaggerSpecJSON, \"\")\n") + b.WriteString("// decodeOpenAPISpec decodes and decompresses the embedded spec.\n") + b.WriteString("func decodeOpenAPISpec() ([]byte, error) {\n") + b.WriteString("\tjoined := strings.Join(openAPISpecJSON, \"\")\n") b.WriteString("\traw, err := base64.StdEncoding.DecodeString(joined)\n") b.WriteString("\tif err != nil {\n") b.WriteString("\t\treturn nil, fmt.Errorf(\"decoding base64: %w\", err)\n") @@ -68,24 +68,24 @@ func generateEmbeddedSpec(specData []byte) (string, error) { b.WriteString("\treturn out.Bytes(), nil\n") b.WriteString("}\n\n") - b.WriteString("// decodeSwaggerSpecCached returns a closure that caches the decoded spec.\n") - b.WriteString("func decodeSwaggerSpecCached() func() ([]byte, error) {\n") + b.WriteString("// decodeOpenAPISpecCached returns a closure that caches the decoded spec.\n") + b.WriteString("func decodeOpenAPISpecCached() func() ([]byte, error) {\n") b.WriteString("\tvar cached []byte\n") b.WriteString("\tvar cachedErr error\n") b.WriteString("\tvar once sync.Once\n") b.WriteString("\treturn func() ([]byte, error) {\n") b.WriteString("\t\tonce.Do(func() {\n") - b.WriteString("\t\t\tcached, cachedErr = decodeSwaggerSpec()\n") + b.WriteString("\t\t\tcached, cachedErr = decodeOpenAPISpec()\n") b.WriteString("\t\t})\n") b.WriteString("\t\treturn cached, cachedErr\n") b.WriteString("\t}\n") b.WriteString("}\n\n") - b.WriteString("var swaggerSpec = decodeSwaggerSpecCached()\n\n") + b.WriteString("var openAPISpec = decodeOpenAPISpecCached()\n\n") - b.WriteString("// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes.\n") - b.WriteString("func GetSwaggerSpecJSON() ([]byte, error) {\n") - b.WriteString("\treturn swaggerSpec()\n") + b.WriteString("// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes.\n") + b.WriteString("func GetOpenAPISpecJSON() ([]byte, error) {\n") + b.WriteString("\treturn openAPISpec()\n") b.WriteString("}\n") return b.String(), nil diff --git a/experimental/internal/codegen/inline_test.go b/experimental/internal/codegen/inline_test.go index ae35938493..233aab2e79 100644 --- a/experimental/internal/codegen/inline_test.go +++ b/experimental/internal/codegen/inline_test.go @@ -19,19 +19,19 @@ func TestGenerateEmbeddedSpec(t *testing.T) { require.NoError(t, err) // Should contain the chunked base64 variable - assert.Contains(t, code, "var swaggerSpecJSON = []string{") + assert.Contains(t, code, "var openAPISpecJSON = []string{") // Should contain the decode function - assert.Contains(t, code, "func decodeSwaggerSpec() ([]byte, error)") + assert.Contains(t, code, "func decodeOpenAPISpec() ([]byte, error)") // Should contain the cached decode function - assert.Contains(t, code, "func decodeSwaggerSpecCached() func() ([]byte, error)") + assert.Contains(t, code, "func decodeOpenAPISpecCached() func() ([]byte, error)") // Should contain the public API - assert.Contains(t, code, "func GetSwaggerSpecJSON() ([]byte, error)") + assert.Contains(t, code, "func GetOpenAPISpecJSON() ([]byte, error)") // Should contain the cached var - assert.Contains(t, code, "var swaggerSpec = decodeSwaggerSpecCached()") + assert.Contains(t, code, "var openAPISpec = decodeOpenAPISpecCached()") } func TestGenerateEmbeddedSpecRoundTrip(t *testing.T) { @@ -101,8 +101,8 @@ components: assert.Contains(t, code, "type Pet struct") // Should contain the embedded spec - assert.Contains(t, code, "GetSwaggerSpecJSON") - assert.Contains(t, code, "swaggerSpecJSON") + assert.Contains(t, code, "GetOpenAPISpecJSON") + assert.Contains(t, code, "openAPISpecJSON") } func TestGenerateWithNilSpecData(t *testing.T) { @@ -134,6 +134,6 @@ components: assert.Contains(t, code, "type Pet struct") // Should NOT contain the embedded spec - assert.NotContains(t, code, "GetSwaggerSpecJSON") - assert.NotContains(t, code, "swaggerSpecJSON") + assert.NotContains(t, code, "GetOpenAPISpecJSON") + assert.NotContains(t, code, "openAPISpecJSON") } diff --git a/experimental/internal/codegen/templates/files/client/base.go.tmpl b/experimental/internal/codegen/templates/files/client/base.go.tmpl index 96d32997f4..04aebaf713 100644 --- a/experimental/internal/codegen/templates/files/client/base.go.tmpl +++ b/experimental/internal/codegen/templates/files/client/base.go.tmpl @@ -14,7 +14,7 @@ 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. + // paths in the OpenAPI spec will be appended to the server. Server string // Doer for performing requests, typically a *http.Client with any diff --git a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go index 633aa2dbe7..04a06f9db5 100644 --- a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go +++ b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go @@ -2009,7 +2009,7 @@ var ErrNullableNotSpecified = errors.New("nullable value is not specified") type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/+wcXW8iOfKdX2Gx+3Zi8jGz84B0D4QwEnsEEJCdi1Z7J4cuEu90u3vcJgm32v9+st10", "tz/6y2RGs6PNEynb9eVyVblcECdAcUKGqP/2zcWb836P0F087CHECQ9hiMZxlDB4BJqSJ0AbSDlabx8h", "wj2EnoClJKZD1L94cy7WIhRAumUk4RIsZqcIhyFK5RKUYM6B0RTtYoZinJDBNg7gAWivl2D+mAq6ZymJ", @@ -2058,9 +2058,9 @@ var swaggerSpecJSON = []string{ "wdmxH1N53dOFMHa0aR81yf8fAAD//ynhbdUwSwAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -2077,22 +2077,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go index 7c5a5d2fa1..a2e22ce566 100644 --- a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go @@ -137,7 +137,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/6yQzY7UMBCE736KknJlMrPsibwBJySExNmb1CQNjm2527MaId4dOeFnZw4Iob25q7vr", "a1eH96qVeDi9fTcgRX44Q61InMFYV8XZS2iVJcyMLN6IXFJmCVfXYTHLOhyPs9hSn/oxrcfksxzGNHFm", "vC2kofTYWK5zHT4vjKja7Hfys9iCtQaTHIjWCDxcfKi8OeqN62ALfx80oRGgS6qhvdcsgfBxwnMqXzGm", @@ -146,9 +146,9 @@ var swaggerSpecJSON = []string{ "vDLjdD/9X0Z+NLnwbz4/AgAA//+mSD78zgIAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -165,22 +165,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go index d996cfb752..8077efc300 100644 --- a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go @@ -238,7 +238,7 @@ var ErrNullableIsNull = errors.New("nullable value is null") var ErrNullableNotSpecified = errors.New("nullable value is not specified") // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/7RUTY/TMBC9+1eMEqReaNNlT+QGnFYIdgXcKzeZJl5S23gmqJX48SjfSZu0ge7eEnvm", "vTdvxuPDA1GOcLe+fx/C1zzL5DZD4KNFggQ1OsnKaOFDymwpDIJEcZpvV5HZB0ZatYxMjAnq4Y8qQCko", "UIUvfPgifyJQ7hA4lQx6yCMdNlwYg3XGosuOwljU0qoQ7lfr1Z1QemdCAfAbHSmjQ1isi/OFAGDFGYaA", @@ -251,9 +251,9 @@ var swaggerSpecJSON = []string{ "wsAUMWu+r+32upa3F5/AWDEyU5I2/1DSlXK649EGvLR7o1R/AwAA///zkywGmQkAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -270,22 +270,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go index 7fd6bbf827..8b54637dde 100644 --- a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go @@ -63,7 +63,7 @@ func (s *TestField3) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/9xUzZKbMAy+8xSapFdCIO106lv30Jkc2kOnL+AYBbwDltcS283bd2zYAJt0Z3otJ/xZ", "P58+WdrCkXlAKA9fPit40GwNyMUjNOgwaLHk4LeVFl7yhvJ4kzvdY7aFVsSzKorGSjucdob6grS3uaEa", "G3Trg41JuIhZMvLotLcKNofdflduMuvOpDIAsdKhWhCCX8iSATxjYEtOQbnb7/aZod6TQyccvdi02Ov0", @@ -74,9 +74,9 @@ var swaggerSpecJSON = []string{ "sy3mLVJMK6SI1DdXDuzJ8bIz1f7jX1vfENXZnwAAAP//PTfE300FAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -93,22 +93,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go index 993992b0d7..5cbd404ef6 100644 --- a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go @@ -100,7 +100,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/6xSsW7cMAzd9RUPcYEsvfMl7VJtHTN1KdBZtmlLwZkURLrF/X0hOwdfrh3DiXqkHt8T", "1eBFdSE8fX3+5kG8zGAxTMRUgtGAP5EYi9YsWUTgy4/RNYhmWX3bTsni0h17mVsJOR16GWgifn9IdYS2", "dYZrXINflTMgF8lU7ILEmgZC4I0eM80dFcSgFauiPsMibfLsksk10CjLeUBHu9ajk0wccvL4cjwdTy7x", @@ -109,9 +109,9 @@ var swaggerSpecJSON = []string{ "dQP7yMN1S+nWXo0x0Xn4fi9uY1QriaePJdmifoF/H+SAUeQ/aBeK+xsAAP//dJpKJ+ICAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -128,22 +128,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go index 2f95e2dbf8..6e3f8a4fa6 100644 --- a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go @@ -117,7 +117,7 @@ func (s *GetSomething200ResponseJSONAnyOf12) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/7xTTW+bQBC98yue4ksrJeC0VaVy66nyKVJTqcdoDWOYyMxud4ZY/vfVgqlJncTJJZyY", "fTP7PhgWWKn2hOsv376W+C5e9p3vFX59T5VBq5Y6hx1bCy90s0FDQtEZKVge3JZrcE1ivGGK2QKtWdCy", "KBq2tl/nle8K7wJfVb6mhuRxwYlai8SdLbIFfrckcAKWLQtN5CxwiKTBixJ6JYWT/c2mGARdwlr6p6qG", @@ -128,9 +128,9 @@ var swaggerSpecJSON = []string{ "b+Ed17Om810T/fgrn23vSNU1b7j3kPjfAAAA///mDrwBGwUAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -147,22 +147,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go index 6efb31f3a5..92bee3e2c8 100644 --- a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go @@ -161,7 +161,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/9SUT4/TMBDF7/kUIwWpFzZpxQEpRzhxQMuhEmc3eYmNEtt4JvtHiO+O4qYbh2132RVC", "oqfO68zzm5+b5PSJeQTt3u+2FbUGfUO9YyFjyYIFDam+v27JWVy3WU5axHNVlp0RPR6K2g2lU95c1a5B", "B7suzOTN5WSe5VlOXzUsjWxstza/NaKPJ7ydlGMOJtZu7Bs6gHwAI9ygKbKc9hq08cENXjZz5FvFdMDk", @@ -172,9 +172,9 @@ var swaggerSpecJSON = []string{ "6CmTS9yXNf97QoK7lxBaXkt/TOhXAAAA//+WRkFKuQYAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -191,22 +191,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go index 33a950f497..39adf0b5c2 100644 --- a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go @@ -23,7 +23,7 @@ func (s *Person) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/6yQvW7jQAyE+32KAVzbsuHK21151fkV1itK4kG73FtSFwRB3j2QHP8BMZAiHTn4SM5w", "hd+qE2F32Hv8Gsc/HV7YBoS2ZWPJYTxWKVSNSZGo9px7t8JgVtQ3Tc82TKdNlNRIKLyO0lJP+bHh+YI2", "u8PeSaEcCnvsN9vN1nHuxDvA2EbyMFKDxoFScMB/qsqSPXYLW4IN6vH27qKkIpmy6Tx75pcSOFJVyeca", @@ -31,9 +31,9 @@ var swaggerSpecJSON = []string{ "LbU6P/2WoiwhoYUidxx/Ns4zjzkk+pa/5VL/hM1TOlF1HwEAAP//7z/Hg3YCAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -50,22 +50,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go index 43d8ca049e..644b5df861 100644 --- a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go @@ -31,7 +31,7 @@ func (s *Bar) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/3xSwY6bMBC98xVPS6VcmpBNbxz3sFJPvVTqNQYP2CvwuJ5hq/x9BSQ16UbLBfzmzXsz", "z5T4LjIRTs/HUw0zDD86/PHqEBNHSupJYBRiRsJA7zRgf1dKBN8HTmSLEk41Sl1VvVc3NYeWx4pN9PuW", "LfUU7g9+9pVqNi7KosQvRwEG0joaDZwRNKwO5+x2hgkW52XI8zyVOtpM9rUoF2QznqXOB7KwPlGrwwUc", @@ -42,9 +42,9 @@ var swaggerSpecJSON = []string{ "AwAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -61,22 +61,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go index f5f81dbf6e..b844e76c4f 100644 --- a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go @@ -43,7 +43,7 @@ func (s *Error) ApplyDefaults() { type ValidatePetsJSONResponse = []Pet // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/8SVTW/bPAzH7/oURPMAOdVOk5uOzzAMvQw5DLurMm2rtSVNpLsFw777IDmu7TpxsQ3D", "bjEpkb8/X5QN3BN1CIe7vYSj4hqQtPLGVmIDNbMnmeeV4bp7yLRrc6e8udWuwArt/MPEOJQf7vZiA+9q", "1E8EPjiP4SUkuBK84prgq+EayKM2qgFdq6A0YyBozBOCdo2zJJxHq7yRcHPIdtnuRhhbOikAnjGQcVbC", @@ -57,9 +57,9 @@ var swaggerSpecJSON = []string{ "6AcAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -76,22 +76,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go index cda70dd5ea..a459a0a12a 100644 --- a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go @@ -178,7 +178,7 @@ var ErrNullableIsNull = errors.New("nullable value is null") var ErrNullableNotSpecified = errors.New("nullable value is not specified") // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/5SRQWvcMBSE7/oVAy7kkqy3KbnoVnrqaS+BnrXys/1a+T0hPbcsIf+92NnueqEQcrNH", "M8ynUYPvtc6Ep/2jR5DToW9DSocef9hGqKQTVAiFetgpEwYSKsGogsWo9CHSy6trMJrl6tt2YBvn4y7q", "1GrI/BC1o4Hk9oeXyto+7R9d4xr8GEneuqEFb/VjqDftVEgi3YMNddQ5dRcS18DGjadbQe8halvGndNM", @@ -188,9 +188,9 @@ var swaggerSpecJSON = []string{ "AAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -207,22 +207,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go index 72354dfa93..06e8ba7b45 100644 --- a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go @@ -37,7 +37,7 @@ func (s *Value) ApplyDefaults() { type ArrayValue = []Value // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/5xQTWvcMBC961c8sgWdarlbctEtUCihlJYeelfkWVupLQnNOHShP77Y3g/vJvQjOknz", "3rwPbXDPPBJutxbfyI+FwxNB9pkYnYtNH2KrNuhEMltj2iDd+FD5NJjkcnjrU0MtxctHmBTZ3G7VRm3w", "2f0g8FgI0jlBuTJxhRYjapBLylT6vUqZosvB4n1VV1sV4i5ZBTxR4ZCiha6runqnFSBBerKgn27IPSmg", @@ -47,9 +47,9 @@ var swaggerSpecJSON = []string{ "d3faWBLePVNYjGblwyQIDauA/9D9dwAAAP//+4PlsMkDAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -66,22 +66,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go index 071c05c0f4..3197d9cfaf 100644 --- a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go @@ -61,7 +61,7 @@ func (d *Date) UnmarshalText(data []byte) error { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/2SSz86bMBDE7zzFiPTamLaKovhWqZfc8gaVYzbgCryWd9M/b18Z+ET8fZzY0c74N+AD", "riJPwul8sfg+BSfUQ/8lEvwJOqJ3Snhwnp02B4yqSawxQ9DxeT96ng27FD577mmgWA+hBIs5nS8NJ4ou", "BYv227E7dm0T4oNtA/ymLIGjxZeiN4AGncjuUFASbZLTUcq+SZPzNPLUUy4zMJCuLwAnyk4Dx2tvi37b", @@ -70,9 +70,9 @@ var swaggerSpecJSON = []string{ "1JW1sv0PAAD//3OxuKeDAgAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -89,22 +89,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go index 1a342a9e92..be13202ea5 100644 --- a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go @@ -32,7 +32,7 @@ func (s *X) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/3yQwWrcMBCG73qKH1zIpbE3KSRExx4KPbWHQNvj2Jq1psiS0MwGSum7lyhZ3NKyt/Hv", "bzTfzICPqifG3cO9x+dWKjcTVmSmBkrp0xHUGLLm0ji4AdGsqp+mVSye5nEp21SoyvVSAq+c//6Q57d1", "unu4d4Mb8CVyBkGXyBshkmIuFs9jckDdBchgkaG0MRI/cXrrhp78wWgspxQwMyQv6RQ4QHKHVs7cyDjA", @@ -41,9 +41,9 @@ var swaggerSpecJSON = []string{ "pt1repWaus/VheF0cWjX+5eQbLxy+9+avwMAAP//FjslWWwCAAA=", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -60,22 +60,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go index 1cd65cb493..f709f7be1c 100644 --- a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go @@ -38,7 +38,7 @@ func (s *TestObjectDateProperty) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/6xQQW7bMBC88xUD61hYclEYAviDntxD+wBKWkvbSFyCu4phBPl7IFmOnXtunOHM7OwW", "+K06E+r66BHG8XTGD5wlT8GQAyspdm2IiGKYKPcEjq1MKRg3I21K3YFyluwKDGZJfVX1bMPclK1MlYTE", "+1Y66il+BbyM1qquj65wBf4px34rYYLQdQj3LgtGE5Rg10TQQeaxw0XyCy5sg8x2q6Clk0QxJPb4VR7K", @@ -46,9 +46,9 @@ var swaggerSpecJSON = []string{ "ysakdxEwz9z9ufHXB3u3q2WO/RO93uJZB+y3i/g16/OrC0bfFbxkuY8AAAD//xKKQGYZAgAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -65,22 +65,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go index d9dd314469..94d3f095c7 100644 --- a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go @@ -41,7 +41,7 @@ func (s *DocumentStatus) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/9RSPYvbQBDt9Sse54AaW1Lk5tg6EI4UKS5dCGFvPZb2sHaWnZFzgfz4IMkfkiHE7XWa", "maf3wb4VnkR6wuO2NnjbNLzR35E2wXaEPSdQ6DsMK8lWaFWjmLJsvLb9S+G4K9lGv3G8o4bCcvADr5SP", "2zrjSMFGb7AtqqLOfNizyYAjJfEcDPKqqIqPeQao1wMZ0Jvt4oEyYEfiko864v5kAPCNRG+t8pFS8ruZ", @@ -51,9 +51,9 @@ var swaggerSpecJSON = []string{ "7LlPPxaBnhfid8Y62kP/71x/AwAA//+qyWhEFgQAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -70,22 +70,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go index 3bbe71257a..8e35db9031 100644 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go @@ -21,7 +21,7 @@ func (s *N3GPPFooJSONResponse) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/2yPsXLqMBBFe33FHdMbP+hUM48wKaDIDyj2Ii9xtBrtQiZ/nzGBsUmiStK5ujq7wE71", "TB77TCUYS8JuA7VQjFPEB1uPjiObW+CF1BTWB4PM0oqB3wjVens4/BepECmNlHAJA3fYCrijZHxkKuok", "UwqZPdZ1U68cp6N4B1yoKEvyqJq6qf9VDjC2gTyeKHTYjA6PkqOOy8F6Hd8v1zHn5VGuZUAk+95gct11", @@ -29,9 +29,9 @@ var swaggerSpecJSON = []string{ "C+YyjmA815zWJQxn+gvcW9UKp+i+AgAA//9y+0ZQ6gEAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -48,22 +48,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go index ac2d373dde..2b95537fbc 100644 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go @@ -31,7 +31,7 @@ const ( type GetFooJSONResponse = []Bar // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/2SRQYujQBCF7/0rHpMFT6PO7M1jYAfCwu5l76ExFdOLVjVdlSz590urQU1u1veq3ie6", "w0H1Sg0OfU+d70F8HcB+IHU7/CE1nVArrObZ0BFT8haE8S/YBTefglwVdOoIrVdSJ5HYx9Dge1mXn84F", "PkvjAAvWr1Q/cu+vrBpFDrhR0iDcoC7rsnYuertovqzOMjYAHdn0AEicX+RwajL/EpmTRBqFlfSxCnzW", @@ -40,9 +40,9 @@ var swaggerSpecJSON = []string{ "iRxX89vHm/sfAAD//5W/OQySAgAA", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -59,22 +59,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go index 8e9cb4c44b..6da0efc8ad 100644 --- a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go +++ b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go @@ -350,7 +350,7 @@ func (s *AllOfWithOneOfAllOf1OneOf1) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ +var openAPISpecJSON = []string{ "H4sIAAAAAAAC/7yTQY/TMBCF7/kVT+W8K5bl5FvgTjggcXbTSTKQjC17WlQh/juKk9KkTVqBKnpq5nnG", "75uXOE9iPRtsXp9fnt9uMpbKmQxQ1pYMPlFU2iGv60C1VcIXipoBBwqRnRhsUpe32kSDn7+y0nXeCYnG", "fkosG+ps+gu8wUcbCS8GeQj2iB+sDawciwqs1MV0KElFlffloQ3QoycD2ytjJZ0/yRiGnB+Bp7EnamCp", @@ -360,9 +360,9 @@ var swaggerSpecJSON = []string{ "2z7cT+N3AAAA//8nzKKtgAUAAA==", } -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") +// decodeOpenAPISpec decodes and decompresses the embedded spec. +func decodeOpenAPISpec() ([]byte, error) { + joined := strings.Join(openAPISpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -379,22 +379,22 @@ func decodeSwaggerSpec() ([]byte, error) { return out.Bytes(), nil } -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { +// decodeOpenAPISpecCached returns a closure that caches the decoded spec. +func decodeOpenAPISpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() + cached, cachedErr = decodeOpenAPISpec() }) return cached, cachedErr } } -var swaggerSpec = decodeSwaggerSpecCached() +var openAPISpec = decodeOpenAPISpecCached() -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() +// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetOpenAPISpecJSON() ([]byte, error) { + return openAPISpec() } From af027b0c66fa15931366a346c462cd959aca73ea Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 5 Feb 2026 09:07:59 +0000 Subject: [PATCH 153/293] docs(sponsors): update section Thanks to Speakeasy and LivePeer for their support over the years! --- README.md | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/README.md b/README.md index b5ed0c8b98..ecf9a55e66 100644 --- a/README.md +++ b/README.md @@ -4478,7 +4478,7 @@ Please consider sponsoring us through GitHub Sponsors either [on the organisatio 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. -In addition, we are also 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:

@@ -4490,30 +4490,10 @@ In addition, we are also generously sponsored by the following folks, each of wh

-

- - - - - Speakeasy logo - - -

-

Cybozu logo

-

- - - - - Livepeer logo - - -

- (Note that the order of appearance the order in which sponsorship was received) From 58bb3e67c25c1cf1d3207b7547504c5e465e6f11 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 7 Feb 2026 09:02:51 +0000 Subject: [PATCH 154/293] Revert "Rename Swagger references to OpenAPI (#2202)" This reverts commit 17ba42e132420ffe0b67b15fafa4750ab144b1c5. --- .../examples/callback/treefarm.gen.go | 22 ++++++++--------- .../petstore-expanded/petstore.gen.go | 22 ++++++++--------- .../examples/webhook/doorbadge.gen.go | 22 ++++++++--------- experimental/internal/codegen/inline.go | 24 +++++++++---------- experimental/internal/codegen/inline_test.go | 18 +++++++------- .../templates/files/client/base.go.tmpl | 2 +- .../comprehensive/output/comprehensive.gen.go | 22 ++++++++--------- .../issues/issue_1029/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1039/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1397/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1429/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1496/output/types.gen.go | 22 ++++++++--------- .../issues/issue_1710/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_193/output/types.gen.go | 22 ++++++++--------- .../issues/issue_2102/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_312/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_502/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_52/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_579/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_697/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_775/output/types.gen.go | 22 ++++++++--------- .../test/issues/issue_832/output/types.gen.go | 22 ++++++++--------- .../output/types.gen.go | 22 ++++++++--------- .../output/types.gen.go | 22 ++++++++--------- .../output/nested_aggregate.gen.go | 22 ++++++++--------- 25 files changed, 264 insertions(+), 264 deletions(-) diff --git a/experimental/examples/callback/treefarm.gen.go b/experimental/examples/callback/treefarm.gen.go index 6d74b06f80..a1018c08e9 100644 --- a/experimental/examples/callback/treefarm.gen.go +++ b/experimental/examples/callback/treefarm.gen.go @@ -80,7 +80,7 @@ func (s *Error) ApplyDefaults() { type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/8RXwW7bOBC96ysGaQG3QCO76U23bJEFAhSbIHGQ44IWxxYbilTJUbzG7gL7EfuF+yUL", "khJFy4rr9NKcopDzZvhm5s1EN6hYIwo4+5R/zBdnmVBrXWQAz2is0KqAj/kiX2QAJEhiAUuDCL8yU2cA", "HG1pREP+3l8ZAMAlkLvQSKZIqA1YNM+iRKCKEXCstbJkGKGFmwbV5e01lEzKFSufbO4BlhVCKQUqAtuu", @@ -103,9 +103,9 @@ var openAPISpecJSON = []string{ "36d8LLPs/wAAAP//y9dX5mEQAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -122,24 +122,24 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } // ServerInterface represents all server handlers. diff --git a/experimental/examples/petstore-expanded/petstore.gen.go b/experimental/examples/petstore-expanded/petstore.gen.go index c958265c74..4149df2b00 100644 --- a/experimental/examples/petstore-expanded/petstore.gen.go +++ b/experimental/examples/petstore-expanded/petstore.gen.go @@ -46,7 +46,7 @@ func (s *Error) ApplyDefaults() { type FindPetsJSONResponse = []Pet // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/+xXXW9byQ19168gtgXyoly5yaIPemo2TgED3cStd/tOz6UkLubLQ44coe1/Lzj3Srqy", "ZG+CYvuF9YMNz3A4hzyHHN6UKWLmJXzztrvqrr6ZcVyl5QxgS0U4xSX8ztZnAMrqaQl3j7heU4FbUtFU", "aAbQk7jCWZv5OxAM2RO8u70B3aBCFRJAyOMBQAGMQJ8HM03QU0hRtKASrAi1FhLgCLoh+JQpmqe33RVI", @@ -77,9 +77,9 @@ var openAPISpecJSON = []string{ "5gbvFMOI4GujHzzt4f8zAAD//6ZcwVZEFgAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -96,22 +96,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/examples/webhook/doorbadge.gen.go b/experimental/examples/webhook/doorbadge.gen.go index b51b7d405f..702d74db62 100644 --- a/experimental/examples/webhook/doorbadge.gen.go +++ b/experimental/examples/webhook/doorbadge.gen.go @@ -72,7 +72,7 @@ const ( type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/9RWTY/bNhC961cM0gI+RfLu9qTbJuvDAkGycFL0TItjaxKJZIaUvEbb/16Q1GdX3l0D", "RZv6ZEnDmfceh4+jDSphKIc3N+lVun6TkNrrPAFokS1plcNVuk7XCYAjV2EOd1ozvBPygLBFIZETAIm2", "YDIuxP+RAADcgvSBuxDIIRAscksFgiuFA4m1VtaxcGjhk0F1+3APN+kVHHFXav3NpiHP+4pQOQuMB7IO", @@ -91,9 +91,9 @@ var openAPISpecJSON = []string{ "xUw9/L8CAAD//+XREy3yDQAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -110,24 +110,24 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } // ServerInterface represents all server handlers. diff --git a/experimental/internal/codegen/inline.go b/experimental/internal/codegen/inline.go index 1a9554f73e..25767cffa8 100644 --- a/experimental/internal/codegen/inline.go +++ b/experimental/internal/codegen/inline.go @@ -9,7 +9,7 @@ import ( ) // generateEmbeddedSpec produces Go code that embeds the raw OpenAPI spec as -// gzip+base64 encoded data, with a public GetOpenAPISpecJSON() function to +// gzip+base64 encoded data, with a public GetSwaggerSpecJSON() function to // retrieve the decompressed JSON bytes. func generateEmbeddedSpec(specData []byte) (string, error) { // Gzip compress @@ -43,15 +43,15 @@ func generateEmbeddedSpec(specData []byte) (string, error) { var b strings.Builder b.WriteString("// Base64-encoded, gzip-compressed OpenAPI spec.\n") - b.WriteString("var openAPISpecJSON = []string{\n") + b.WriteString("var swaggerSpecJSON = []string{\n") for _, chunk := range chunks { fmt.Fprintf(&b, "\t%q,\n", chunk) } b.WriteString("}\n\n") - b.WriteString("// decodeOpenAPISpec decodes and decompresses the embedded spec.\n") - b.WriteString("func decodeOpenAPISpec() ([]byte, error) {\n") - b.WriteString("\tjoined := strings.Join(openAPISpecJSON, \"\")\n") + b.WriteString("// decodeSwaggerSpec decodes and decompresses the embedded spec.\n") + b.WriteString("func decodeSwaggerSpec() ([]byte, error) {\n") + b.WriteString("\tjoined := strings.Join(swaggerSpecJSON, \"\")\n") b.WriteString("\traw, err := base64.StdEncoding.DecodeString(joined)\n") b.WriteString("\tif err != nil {\n") b.WriteString("\t\treturn nil, fmt.Errorf(\"decoding base64: %w\", err)\n") @@ -68,24 +68,24 @@ func generateEmbeddedSpec(specData []byte) (string, error) { b.WriteString("\treturn out.Bytes(), nil\n") b.WriteString("}\n\n") - b.WriteString("// decodeOpenAPISpecCached returns a closure that caches the decoded spec.\n") - b.WriteString("func decodeOpenAPISpecCached() func() ([]byte, error) {\n") + b.WriteString("// decodeSwaggerSpecCached returns a closure that caches the decoded spec.\n") + b.WriteString("func decodeSwaggerSpecCached() func() ([]byte, error) {\n") b.WriteString("\tvar cached []byte\n") b.WriteString("\tvar cachedErr error\n") b.WriteString("\tvar once sync.Once\n") b.WriteString("\treturn func() ([]byte, error) {\n") b.WriteString("\t\tonce.Do(func() {\n") - b.WriteString("\t\t\tcached, cachedErr = decodeOpenAPISpec()\n") + b.WriteString("\t\t\tcached, cachedErr = decodeSwaggerSpec()\n") b.WriteString("\t\t})\n") b.WriteString("\t\treturn cached, cachedErr\n") b.WriteString("\t}\n") b.WriteString("}\n\n") - b.WriteString("var openAPISpec = decodeOpenAPISpecCached()\n\n") + b.WriteString("var swaggerSpec = decodeSwaggerSpecCached()\n\n") - b.WriteString("// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes.\n") - b.WriteString("func GetOpenAPISpecJSON() ([]byte, error) {\n") - b.WriteString("\treturn openAPISpec()\n") + b.WriteString("// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes.\n") + b.WriteString("func GetSwaggerSpecJSON() ([]byte, error) {\n") + b.WriteString("\treturn swaggerSpec()\n") b.WriteString("}\n") return b.String(), nil diff --git a/experimental/internal/codegen/inline_test.go b/experimental/internal/codegen/inline_test.go index 233aab2e79..ae35938493 100644 --- a/experimental/internal/codegen/inline_test.go +++ b/experimental/internal/codegen/inline_test.go @@ -19,19 +19,19 @@ func TestGenerateEmbeddedSpec(t *testing.T) { require.NoError(t, err) // Should contain the chunked base64 variable - assert.Contains(t, code, "var openAPISpecJSON = []string{") + assert.Contains(t, code, "var swaggerSpecJSON = []string{") // Should contain the decode function - assert.Contains(t, code, "func decodeOpenAPISpec() ([]byte, error)") + assert.Contains(t, code, "func decodeSwaggerSpec() ([]byte, error)") // Should contain the cached decode function - assert.Contains(t, code, "func decodeOpenAPISpecCached() func() ([]byte, error)") + assert.Contains(t, code, "func decodeSwaggerSpecCached() func() ([]byte, error)") // Should contain the public API - assert.Contains(t, code, "func GetOpenAPISpecJSON() ([]byte, error)") + assert.Contains(t, code, "func GetSwaggerSpecJSON() ([]byte, error)") // Should contain the cached var - assert.Contains(t, code, "var openAPISpec = decodeOpenAPISpecCached()") + assert.Contains(t, code, "var swaggerSpec = decodeSwaggerSpecCached()") } func TestGenerateEmbeddedSpecRoundTrip(t *testing.T) { @@ -101,8 +101,8 @@ components: assert.Contains(t, code, "type Pet struct") // Should contain the embedded spec - assert.Contains(t, code, "GetOpenAPISpecJSON") - assert.Contains(t, code, "openAPISpecJSON") + assert.Contains(t, code, "GetSwaggerSpecJSON") + assert.Contains(t, code, "swaggerSpecJSON") } func TestGenerateWithNilSpecData(t *testing.T) { @@ -134,6 +134,6 @@ components: assert.Contains(t, code, "type Pet struct") // Should NOT contain the embedded spec - assert.NotContains(t, code, "GetOpenAPISpecJSON") - assert.NotContains(t, code, "openAPISpecJSON") + assert.NotContains(t, code, "GetSwaggerSpecJSON") + assert.NotContains(t, code, "swaggerSpecJSON") } diff --git a/experimental/internal/codegen/templates/files/client/base.go.tmpl b/experimental/internal/codegen/templates/files/client/base.go.tmpl index 04aebaf713..96d32997f4 100644 --- a/experimental/internal/codegen/templates/files/client/base.go.tmpl +++ b/experimental/internal/codegen/templates/files/client/base.go.tmpl @@ -14,7 +14,7 @@ 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 OpenAPI spec will be appended to the server. + // paths in the swagger spec will be appended to the server. Server string // Doer for performing requests, typically a *http.Client with any diff --git a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go index 04a06f9db5..633aa2dbe7 100644 --- a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go +++ b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go @@ -2009,7 +2009,7 @@ var ErrNullableNotSpecified = errors.New("nullable value is not specified") type UUID = uuid.UUID // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/+wcXW8iOfKdX2Gx+3Zi8jGz84B0D4QwEnsEEJCdi1Z7J4cuEu90u3vcJgm32v9+st10", "tz/6y2RGs6PNEynb9eVyVblcECdAcUKGqP/2zcWb836P0F087CHECQ9hiMZxlDB4BJqSJ0AbSDlabx8h", "wj2EnoClJKZD1L94cy7WIhRAumUk4RIsZqcIhyFK5RKUYM6B0RTtYoZinJDBNg7gAWivl2D+mAq6ZymJ", @@ -2058,9 +2058,9 @@ var openAPISpecJSON = []string{ "wdmxH1N53dOFMHa0aR81yf8fAAD//ynhbdUwSwAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -2077,22 +2077,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go index a2e22ce566..7c5a5d2fa1 100644 --- a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go @@ -137,7 +137,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/6yQzY7UMBCE736KknJlMrPsibwBJySExNmb1CQNjm2527MaId4dOeFnZw4Iob25q7vr", "a1eH96qVeDi9fTcgRX44Q61InMFYV8XZS2iVJcyMLN6IXFJmCVfXYTHLOhyPs9hSn/oxrcfksxzGNHFm", "vC2kofTYWK5zHT4vjKja7Hfys9iCtQaTHIjWCDxcfKi8OeqN62ALfx80oRGgS6qhvdcsgfBxwnMqXzGm", @@ -146,9 +146,9 @@ var openAPISpecJSON = []string{ "vDLjdD/9X0Z+NLnwbz4/AgAA//+mSD78zgIAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -165,22 +165,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go index 8077efc300..d996cfb752 100644 --- a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go @@ -238,7 +238,7 @@ var ErrNullableIsNull = errors.New("nullable value is null") var ErrNullableNotSpecified = errors.New("nullable value is not specified") // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/7RUTY/TMBC9+1eMEqReaNNlT+QGnFYIdgXcKzeZJl5S23gmqJX48SjfSZu0ge7eEnvm", "vTdvxuPDA1GOcLe+fx/C1zzL5DZD4KNFggQ1OsnKaOFDymwpDIJEcZpvV5HZB0ZatYxMjAnq4Y8qQCko", "UIUvfPgifyJQ7hA4lQx6yCMdNlwYg3XGosuOwljU0qoQ7lfr1Z1QemdCAfAbHSmjQ1isi/OFAGDFGYaA", @@ -251,9 +251,9 @@ var openAPISpecJSON = []string{ "wsAUMWu+r+32upa3F5/AWDEyU5I2/1DSlXK649EGvLR7o1R/AwAA///zkywGmQkAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -270,22 +270,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go index 8b54637dde..7fd6bbf827 100644 --- a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go @@ -63,7 +63,7 @@ func (s *TestField3) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/9xUzZKbMAy+8xSapFdCIO106lv30Jkc2kOnL+AYBbwDltcS283bd2zYAJt0Z3otJ/xZ", "P58+WdrCkXlAKA9fPit40GwNyMUjNOgwaLHk4LeVFl7yhvJ4kzvdY7aFVsSzKorGSjucdob6grS3uaEa", "G3Trg41JuIhZMvLotLcKNofdflduMuvOpDIAsdKhWhCCX8iSATxjYEtOQbnb7/aZod6TQyccvdi02Ov0", @@ -74,9 +74,9 @@ var openAPISpecJSON = []string{ "sy3mLVJMK6SI1DdXDuzJ8bIz1f7jX1vfENXZnwAAAP//PTfE300FAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -93,22 +93,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go index 5cbd404ef6..993992b0d7 100644 --- a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go @@ -100,7 +100,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/6xSsW7cMAzd9RUPcYEsvfMl7VJtHTN1KdBZtmlLwZkURLrF/X0hOwdfrh3DiXqkHt8T", "1eBFdSE8fX3+5kG8zGAxTMRUgtGAP5EYi9YsWUTgy4/RNYhmWX3bTsni0h17mVsJOR16GWgifn9IdYS2", "dYZrXINflTMgF8lU7ILEmgZC4I0eM80dFcSgFauiPsMibfLsksk10CjLeUBHu9ajk0wccvL4cjwdTy7x", @@ -109,9 +109,9 @@ var openAPISpecJSON = []string{ "dQP7yMN1S+nWXo0x0Xn4fi9uY1QriaePJdmifoF/H+SAUeQ/aBeK+xsAAP//dJpKJ+ICAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -128,22 +128,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go index 6e3f8a4fa6..2f95e2dbf8 100644 --- a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go @@ -117,7 +117,7 @@ func (s *GetSomething200ResponseJSONAnyOf12) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/7xTTW+bQBC98yue4ksrJeC0VaVy66nyKVJTqcdoDWOYyMxud4ZY/vfVgqlJncTJJZyY", "fTP7PhgWWKn2hOsv376W+C5e9p3vFX59T5VBq5Y6hx1bCy90s0FDQtEZKVge3JZrcE1ivGGK2QKtWdCy", "KBq2tl/nle8K7wJfVb6mhuRxwYlai8SdLbIFfrckcAKWLQtN5CxwiKTBixJ6JYWT/c2mGARdwlr6p6qG", @@ -128,9 +128,9 @@ var openAPISpecJSON = []string{ "b+Ed17Om810T/fgrn23vSNU1b7j3kPjfAAAA///mDrwBGwUAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -147,22 +147,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go index 92bee3e2c8..6efb31f3a5 100644 --- a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go @@ -161,7 +161,7 @@ const ( ) // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/9SUT4/TMBDF7/kUIwWpFzZpxQEpRzhxQMuhEmc3eYmNEtt4JvtHiO+O4qYbh2132RVC", "oqfO68zzm5+b5PSJeQTt3u+2FbUGfUO9YyFjyYIFDam+v27JWVy3WU5axHNVlp0RPR6K2g2lU95c1a5B", "B7suzOTN5WSe5VlOXzUsjWxstza/NaKPJ7ydlGMOJtZu7Bs6gHwAI9ygKbKc9hq08cENXjZz5FvFdMDk", @@ -172,9 +172,9 @@ var openAPISpecJSON = []string{ "6CmTS9yXNf97QoK7lxBaXkt/TOhXAAAA//+WRkFKuQYAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -191,22 +191,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go index 39adf0b5c2..33a950f497 100644 --- a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go @@ -23,7 +23,7 @@ func (s *Person) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/6yQvW7jQAyE+32KAVzbsuHK21151fkV1itK4kG73FtSFwRB3j2QHP8BMZAiHTn4SM5w", "hd+qE2F32Hv8Gsc/HV7YBoS2ZWPJYTxWKVSNSZGo9px7t8JgVtQ3Tc82TKdNlNRIKLyO0lJP+bHh+YI2", "u8PeSaEcCnvsN9vN1nHuxDvA2EbyMFKDxoFScMB/qsqSPXYLW4IN6vH27qKkIpmy6Tx75pcSOFJVyeca", @@ -31,9 +31,9 @@ var openAPISpecJSON = []string{ "LbU6P/2WoiwhoYUidxx/Ns4zjzkk+pa/5VL/hM1TOlF1HwEAAP//7z/Hg3YCAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -50,22 +50,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go index 644b5df861..43d8ca049e 100644 --- a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go @@ -31,7 +31,7 @@ func (s *Bar) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/3xSwY6bMBC98xVPS6VcmpBNbxz3sFJPvVTqNQYP2CvwuJ5hq/x9BSQ16UbLBfzmzXsz", "z5T4LjIRTs/HUw0zDD86/PHqEBNHSupJYBRiRsJA7zRgf1dKBN8HTmSLEk41Sl1VvVc3NYeWx4pN9PuW", "LfUU7g9+9pVqNi7KosQvRwEG0joaDZwRNKwO5+x2hgkW52XI8zyVOtpM9rUoF2QznqXOB7KwPlGrwwUc", @@ -42,9 +42,9 @@ var openAPISpecJSON = []string{ "AwAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -61,22 +61,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go index b844e76c4f..f5f81dbf6e 100644 --- a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go @@ -43,7 +43,7 @@ func (s *Error) ApplyDefaults() { type ValidatePetsJSONResponse = []Pet // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/8SVTW/bPAzH7/oURPMAOdVOk5uOzzAMvQw5DLurMm2rtSVNpLsFw777IDmu7TpxsQ3D", "bjEpkb8/X5QN3BN1CIe7vYSj4hqQtPLGVmIDNbMnmeeV4bp7yLRrc6e8udWuwArt/MPEOJQf7vZiA+9q", "1E8EPjiP4SUkuBK84prgq+EayKM2qgFdq6A0YyBozBOCdo2zJJxHq7yRcHPIdtnuRhhbOikAnjGQcVbC", @@ -57,9 +57,9 @@ var openAPISpecJSON = []string{ "6AcAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -76,22 +76,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go index a459a0a12a..cda70dd5ea 100644 --- a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go @@ -178,7 +178,7 @@ var ErrNullableIsNull = errors.New("nullable value is null") var ErrNullableNotSpecified = errors.New("nullable value is not specified") // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/5SRQWvcMBSE7/oVAy7kkqy3KbnoVnrqaS+BnrXys/1a+T0hPbcsIf+92NnueqEQcrNH", "M8ynUYPvtc6Ep/2jR5DToW9DSocef9hGqKQTVAiFetgpEwYSKsGogsWo9CHSy6trMJrl6tt2YBvn4y7q", "1GrI/BC1o4Hk9oeXyto+7R9d4xr8GEneuqEFb/VjqDftVEgi3YMNddQ5dRcS18DGjadbQe8halvGndNM", @@ -188,9 +188,9 @@ var openAPISpecJSON = []string{ "AAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -207,22 +207,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go index 06e8ba7b45..72354dfa93 100644 --- a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go @@ -37,7 +37,7 @@ func (s *Value) ApplyDefaults() { type ArrayValue = []Value // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/5xQTWvcMBC961c8sgWdarlbctEtUCihlJYeelfkWVupLQnNOHShP77Y3g/vJvQjOknz", "3rwPbXDPPBJutxbfyI+FwxNB9pkYnYtNH2KrNuhEMltj2iDd+FD5NJjkcnjrU0MtxctHmBTZ3G7VRm3w", "2f0g8FgI0jlBuTJxhRYjapBLylT6vUqZosvB4n1VV1sV4i5ZBTxR4ZCiha6runqnFSBBerKgn27IPSmg", @@ -47,9 +47,9 @@ var openAPISpecJSON = []string{ "d3faWBLePVNYjGblwyQIDauA/9D9dwAAAP//+4PlsMkDAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -66,22 +66,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go index 3197d9cfaf..071c05c0f4 100644 --- a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go @@ -61,7 +61,7 @@ func (d *Date) UnmarshalText(data []byte) error { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/2SSz86bMBDE7zzFiPTamLaKovhWqZfc8gaVYzbgCryWd9M/b18Z+ET8fZzY0c74N+AD", "riJPwul8sfg+BSfUQ/8lEvwJOqJ3Snhwnp02B4yqSawxQ9DxeT96ng27FD577mmgWA+hBIs5nS8NJ4ou", "BYv227E7dm0T4oNtA/ymLIGjxZeiN4AGncjuUFASbZLTUcq+SZPzNPLUUy4zMJCuLwAnyk4Dx2tvi37b", @@ -70,9 +70,9 @@ var openAPISpecJSON = []string{ "1JW1sv0PAAD//3OxuKeDAgAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -89,22 +89,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go index be13202ea5..1a342a9e92 100644 --- a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go @@ -32,7 +32,7 @@ func (s *X) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/3yQwWrcMBCG73qKH1zIpbE3KSRExx4KPbWHQNvj2Jq1psiS0MwGSum7lyhZ3NKyt/Hv", "bzTfzICPqifG3cO9x+dWKjcTVmSmBkrp0xHUGLLm0ji4AdGsqp+mVSye5nEp21SoyvVSAq+c//6Q57d1", "unu4d4Mb8CVyBkGXyBshkmIuFs9jckDdBchgkaG0MRI/cXrrhp78wWgspxQwMyQv6RQ4QHKHVs7cyDjA", @@ -41,9 +41,9 @@ var openAPISpecJSON = []string{ "pt1repWaus/VheF0cWjX+5eQbLxy+9+avwMAAP//FjslWWwCAAA=", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -60,22 +60,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go index f709f7be1c..1cd65cb493 100644 --- a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go @@ -38,7 +38,7 @@ func (s *TestObjectDateProperty) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/6xQQW7bMBC88xUD61hYclEYAviDntxD+wBKWkvbSFyCu4phBPl7IFmOnXtunOHM7OwW", "+K06E+r66BHG8XTGD5wlT8GQAyspdm2IiGKYKPcEjq1MKRg3I21K3YFyluwKDGZJfVX1bMPclK1MlYTE", "+1Y66il+BbyM1qquj65wBf4px34rYYLQdQj3LgtGE5Rg10TQQeaxw0XyCy5sg8x2q6Clk0QxJPb4VR7K", @@ -46,9 +46,9 @@ var openAPISpecJSON = []string{ "ysakdxEwz9z9ufHXB3u3q2WO/RO93uJZB+y3i/g16/OrC0bfFbxkuY8AAAD//xKKQGYZAgAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -65,22 +65,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go index 94d3f095c7..d9dd314469 100644 --- a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go @@ -41,7 +41,7 @@ func (s *DocumentStatus) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/9RSPYvbQBDt9Sse54AaW1Lk5tg6EI4UKS5dCGFvPZb2sHaWnZFzgfz4IMkfkiHE7XWa", "maf3wb4VnkR6wuO2NnjbNLzR35E2wXaEPSdQ6DsMK8lWaFWjmLJsvLb9S+G4K9lGv3G8o4bCcvADr5SP", "2zrjSMFGb7AtqqLOfNizyYAjJfEcDPKqqIqPeQao1wMZ0Jvt4oEyYEfiko864v5kAPCNRG+t8pFS8ruZ", @@ -51,9 +51,9 @@ var openAPISpecJSON = []string{ "7LlPPxaBnhfid8Y62kP/71x/AwAA//+qyWhEFgQAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -70,22 +70,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go index 8e35db9031..3bbe71257a 100644 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go @@ -21,7 +21,7 @@ func (s *N3GPPFooJSONResponse) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/2yPsXLqMBBFe33FHdMbP+hUM48wKaDIDyj2Ii9xtBrtQiZ/nzGBsUmiStK5ujq7wE71", "TB77TCUYS8JuA7VQjFPEB1uPjiObW+CF1BTWB4PM0oqB3wjVens4/BepECmNlHAJA3fYCrijZHxkKuok", "UwqZPdZ1U68cp6N4B1yoKEvyqJq6qf9VDjC2gTyeKHTYjA6PkqOOy8F6Hd8v1zHn5VGuZUAk+95gct11", @@ -29,9 +29,9 @@ var openAPISpecJSON = []string{ "C+YyjmA815zWJQxn+gvcW9UKp+i+AgAA//9y+0ZQ6gEAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -48,22 +48,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go index 2b95537fbc..ac2d373dde 100644 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go +++ b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go @@ -31,7 +31,7 @@ const ( type GetFooJSONResponse = []Bar // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/2SRQYujQBCF7/0rHpMFT6PO7M1jYAfCwu5l76ExFdOLVjVdlSz590urQU1u1veq3ie6", "w0H1Sg0OfU+d70F8HcB+IHU7/CE1nVArrObZ0BFT8haE8S/YBTefglwVdOoIrVdSJ5HYx9Dge1mXn84F", "PkvjAAvWr1Q/cu+vrBpFDrhR0iDcoC7rsnYuertovqzOMjYAHdn0AEicX+RwajL/EpmTRBqFlfSxCnzW", @@ -40,9 +40,9 @@ var openAPISpecJSON = []string{ "iRxX89vHm/sfAAD//5W/OQySAgAA", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -59,22 +59,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go index 6da0efc8ad..8e9cb4c44b 100644 --- a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go +++ b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go @@ -350,7 +350,7 @@ func (s *AllOfWithOneOfAllOf1OneOf1) ApplyDefaults() { } // Base64-encoded, gzip-compressed OpenAPI spec. -var openAPISpecJSON = []string{ +var swaggerSpecJSON = []string{ "H4sIAAAAAAAC/7yTQY/TMBCF7/kVT+W8K5bl5FvgTjggcXbTSTKQjC17WlQh/juKk9KkTVqBKnpq5nnG", "75uXOE9iPRtsXp9fnt9uMpbKmQxQ1pYMPlFU2iGv60C1VcIXipoBBwqRnRhsUpe32kSDn7+y0nXeCYnG", "fkosG+ps+gu8wUcbCS8GeQj2iB+sDawciwqs1MV0KElFlffloQ3QoycD2ytjJZ0/yRiGnB+Bp7EnamCp", @@ -360,9 +360,9 @@ var openAPISpecJSON = []string{ "2z7cT+N3AAAA//8nzKKtgAUAAA==", } -// decodeOpenAPISpec decodes and decompresses the embedded spec. -func decodeOpenAPISpec() ([]byte, error) { - joined := strings.Join(openAPISpecJSON, "") +// decodeSwaggerSpec decodes and decompresses the embedded spec. +func decodeSwaggerSpec() ([]byte, error) { + joined := strings.Join(swaggerSpecJSON, "") raw, err := base64.StdEncoding.DecodeString(joined) if err != nil { return nil, fmt.Errorf("decoding base64: %w", err) @@ -379,22 +379,22 @@ func decodeOpenAPISpec() ([]byte, error) { return out.Bytes(), nil } -// decodeOpenAPISpecCached returns a closure that caches the decoded spec. -func decodeOpenAPISpecCached() func() ([]byte, error) { +// decodeSwaggerSpecCached returns a closure that caches the decoded spec. +func decodeSwaggerSpecCached() func() ([]byte, error) { var cached []byte var cachedErr error var once sync.Once return func() ([]byte, error) { once.Do(func() { - cached, cachedErr = decodeOpenAPISpec() + cached, cachedErr = decodeSwaggerSpec() }) return cached, cachedErr } } -var openAPISpec = decodeOpenAPISpecCached() +var swaggerSpec = decodeSwaggerSpecCached() -// GetOpenAPISpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetOpenAPISpecJSON() ([]byte, error) { - return openAPISpec() +// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. +func GetSwaggerSpecJSON() ([]byte, error) { + return swaggerSpec() } From a5d982065da7a87d781fa84dd97d00462a56ca9a Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 7 Feb 2026 09:02:52 +0000 Subject: [PATCH 155/293] Revert "Add output filtering (#2201)" This reverts commit db8abb866c5b99d169290020eb23416c3c5c79fc. --- experimental/Configuration.md | 20 -- experimental/cmd/oapi-codegen/main.go | 46 +-- experimental/internal/codegen/codegen.go | 9 - .../internal/codegen/configuration.go | 16 - experimental/internal/codegen/filter.go | 97 ------ experimental/internal/codegen/filter_test.go | 323 ------------------ 6 files changed, 5 insertions(+), 506 deletions(-) delete mode 100644 experimental/internal/codegen/filter.go delete mode 100644 experimental/internal/codegen/filter_test.go diff --git a/experimental/Configuration.md b/experimental/Configuration.md index db2d3ed508..55f550e2f3 100644 --- a/experimental/Configuration.md +++ b/experimental/Configuration.md @@ -37,26 +37,6 @@ generation: path: github.com/org/project/models alias: models # optional, defaults to last segment of path -# Output options: control which operations and schemas are included. -output-options: - # Only include operations tagged with one of these tags. Ignored when empty. - include-tags: - - public - - beta - # Exclude operations tagged with one of these tags. Ignored when empty. - exclude-tags: - - internal - # Only include operations with one of these operation IDs. Ignored when empty. - include-operation-ids: - - listPets - - createPet - # Exclude operations with one of these operation IDs. Ignored when empty. - exclude-operation-ids: - - deprecatedEndpoint - # Exclude schemas with the given names from generation. Ignored when empty. - exclude-schemas: - - InternalConfig - # Type mappings: OpenAPI type/format to Go type. # User values are merged on top of defaults — you only need to specify overrides. type-mapping: diff --git a/experimental/cmd/oapi-codegen/main.go b/experimental/cmd/oapi-codegen/main.go index 50205e846c..24c5320c90 100644 --- a/experimental/cmd/oapi-codegen/main.go +++ b/experimental/cmd/oapi-codegen/main.go @@ -3,9 +3,6 @@ package main import ( "flag" "fmt" - "io" - "net/http" - "net/url" "os" "path/filepath" "strings" @@ -23,9 +20,9 @@ func main() { flagPackage := flag.String("package", "", "Go package name for generated code") flagOutput := flag.String("output", "", "output file path (default: .gen.go)") flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Arguments:\n") - fmt.Fprintf(os.Stderr, " spec-path-or-url path or URL to OpenAPI spec file\n\n") + fmt.Fprintf(os.Stderr, " spec-path path to OpenAPI spec file\n\n") fmt.Fprintf(os.Stderr, "Options:\n") flag.PrintDefaults() } @@ -38,8 +35,8 @@ func main() { specPath := flag.Arg(0) - // Load the OpenAPI spec from file or URL - specData, err := loadSpec(specPath) + // Parse the OpenAPI spec + specData, err := os.ReadFile(specPath) if err != nil { fmt.Fprintf(os.Stderr, "error reading spec: %v\n", err) os.Exit(1) @@ -81,12 +78,7 @@ func main() { // Default output to .gen.go if cfg.Output == "" { - // For URLs, extract the filename from the URL path - baseName := specPath - if u, err := url.Parse(specPath); err == nil && u.Scheme != "" && u.Host != "" { - baseName = u.Path - } - base := filepath.Base(baseName) + base := filepath.Base(specPath) ext := filepath.Ext(base) cfg.Output = strings.TrimSuffix(base, ext) + ".gen.go" } @@ -111,31 +103,3 @@ func main() { fmt.Printf("Generated %s\n", cfg.Output) } - -// loadSpec loads an OpenAPI spec from a file path or URL. -func loadSpec(specPath string) ([]byte, error) { - u, err := url.Parse(specPath) - if err == nil && u.Scheme != "" && u.Host != "" { - return loadSpecFromURL(u.String()) - } - return os.ReadFile(specPath) -} - -// loadSpecFromURL fetches an OpenAPI spec from an HTTP(S) URL. -func loadSpecFromURL(specURL string) ([]byte, error) { - resp, err := http.Get(specURL) //nolint:gosec // URL comes from user-provided spec path - if err != nil { - return nil, fmt.Errorf("fetching spec from URL: %w", err) - } - defer func() { _ = resp.Body.Close() }() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("fetching spec from URL: HTTP %d %s", resp.StatusCode, resp.Status) - } - - data, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("reading spec from URL: %w", err) - } - return data, nil -} diff --git a/experimental/internal/codegen/codegen.go b/experimental/internal/codegen/codegen.go index 7ff2175067..5b6fdff894 100644 --- a/experimental/internal/codegen/codegen.go +++ b/experimental/internal/codegen/codegen.go @@ -31,9 +31,6 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering schemas: %w", err) } - // Filter excluded schemas - schemas = FilterSchemasByName(schemas, cfg.OutputOptions.ExcludeSchemas) - // Pass 2: Compute names for all schemas converter := NewNameConverter(cfg.NameMangling, cfg.NameSubstitutions) ComputeSchemaNames(schemas, converter, contentTypeNamer) @@ -105,9 +102,6 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering operations: %w", err) } - // Apply operation filters - ops = FilterOperations(ops, cfg.OutputOptions) - // Generate client clientGen, err := NewClientGenerator(schemaIndex, cfg.Generation.SimpleClient, cfg.Generation.ModelsPackage) if err != nil { @@ -164,9 +158,6 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri return "", fmt.Errorf("gathering operations: %w", err) } - // Apply operation filters - ops = FilterOperations(ops, cfg.OutputOptions) - if len(ops) > 0 { // Generate server serverGen, err := NewServerGenerator(cfg.Generation.Server) diff --git a/experimental/internal/codegen/configuration.go b/experimental/internal/codegen/configuration.go index 0dc128f9ea..c8d1b87388 100644 --- a/experimental/internal/codegen/configuration.go +++ b/experimental/internal/codegen/configuration.go @@ -15,8 +15,6 @@ type Configuration struct { Output string `yaml:"output"` // Generation controls which parts of the code are generated Generation GenerationOptions `yaml:"generation,omitempty"` - // OutputOptions controls filtering of operations and schemas - OutputOptions OutputOptions `yaml:"output-options,omitempty"` // TypeMapping allows customizing OpenAPI type/format to Go type mappings TypeMapping TypeMapping `yaml:"type-mapping,omitempty"` // NameMangling configures how OpenAPI names are converted to Go identifiers @@ -40,20 +38,6 @@ type Configuration struct { StructTags StructTagsConfig `yaml:"struct-tags,omitempty"` } -// OutputOptions controls filtering of which operations and schemas are included in generation. -type OutputOptions struct { - // IncludeTags only includes operations tagged with one of these tags. Ignored when empty. - IncludeTags []string `yaml:"include-tags,omitempty"` - // ExcludeTags excludes operations tagged with one of these tags. Ignored when empty. - ExcludeTags []string `yaml:"exclude-tags,omitempty"` - // IncludeOperationIDs only includes operations with one of these operation IDs. Ignored when empty. - IncludeOperationIDs []string `yaml:"include-operation-ids,omitempty"` - // ExcludeOperationIDs excludes operations with one of these operation IDs. Ignored when empty. - ExcludeOperationIDs []string `yaml:"exclude-operation-ids,omitempty"` - // ExcludeSchemas excludes schemas with the given names from generation. Ignored when empty. - ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` -} - // ModelsPackage specifies an external package containing the model types. type ModelsPackage struct { // Path is the import path for the models package (e.g., "github.com/org/project/models") diff --git a/experimental/internal/codegen/filter.go b/experimental/internal/codegen/filter.go deleted file mode 100644 index 8e20bed5af..0000000000 --- a/experimental/internal/codegen/filter.go +++ /dev/null @@ -1,97 +0,0 @@ -package codegen - -// FilterOperationsByTag filters operations based on include/exclude tag lists. -// Exclude is applied first, then include. -func FilterOperationsByTag(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { - if len(opts.ExcludeTags) > 0 { - tags := sliceToSet(opts.ExcludeTags) - ops = filterOps(ops, func(op *OperationDescriptor) bool { - return !operationHasTag(op, tags) - }) - } - if len(opts.IncludeTags) > 0 { - tags := sliceToSet(opts.IncludeTags) - ops = filterOps(ops, func(op *OperationDescriptor) bool { - return operationHasTag(op, tags) - }) - } - return ops -} - -// FilterOperationsByOperationID filters operations based on include/exclude operation ID lists. -// Exclude is applied first, then include. -func FilterOperationsByOperationID(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { - if len(opts.ExcludeOperationIDs) > 0 { - ids := sliceToSet(opts.ExcludeOperationIDs) - ops = filterOps(ops, func(op *OperationDescriptor) bool { - return !ids[op.OperationID] - }) - } - if len(opts.IncludeOperationIDs) > 0 { - ids := sliceToSet(opts.IncludeOperationIDs) - ops = filterOps(ops, func(op *OperationDescriptor) bool { - return ids[op.OperationID] - }) - } - return ops -} - -// FilterOperations applies all operation filters (tags, operation IDs) from OutputOptions. -func FilterOperations(ops []*OperationDescriptor, opts OutputOptions) []*OperationDescriptor { - ops = FilterOperationsByTag(ops, opts) - ops = FilterOperationsByOperationID(ops, opts) - return ops -} - -// FilterSchemasByName removes schemas whose component name is in the exclude list. -// Only filters top-level component schemas (path: components/schemas/). -func FilterSchemasByName(schemas []*SchemaDescriptor, excludeNames []string) []*SchemaDescriptor { - if len(excludeNames) == 0 { - return schemas - } - excluded := sliceToSet(excludeNames) - result := make([]*SchemaDescriptor, 0, len(schemas)) - for _, s := range schemas { - // Check if this is a top-level component schema - if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { - if excluded[s.Path[2]] { - continue - } - } - result = append(result, s) - } - return result -} - -// operationHasTag returns true if the operation has any of the given tags. -func operationHasTag(op *OperationDescriptor, tags map[string]bool) bool { - if op == nil || op.Spec == nil { - return false - } - for _, tag := range op.Spec.Tags { - if tags[tag] { - return true - } - } - return false -} - -// filterOps returns operations that satisfy the predicate. -func filterOps(ops []*OperationDescriptor, keep func(*OperationDescriptor) bool) []*OperationDescriptor { - result := make([]*OperationDescriptor, 0, len(ops)) - for _, op := range ops { - if keep(op) { - result = append(result, op) - } - } - return result -} - -// sliceToSet converts a string slice to a set (map[string]bool). -func sliceToSet(items []string) map[string]bool { - m := make(map[string]bool, len(items)) - for _, item := range items { - m[item] = true - } - return m -} diff --git a/experimental/internal/codegen/filter_test.go b/experimental/internal/codegen/filter_test.go deleted file mode 100644 index 9e0f960a86..0000000000 --- a/experimental/internal/codegen/filter_test.go +++ /dev/null @@ -1,323 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/pb33f/libopenapi" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const filterTestSpec = `openapi: "3.1.0" -info: - title: Filter Test API - version: "1.0" -paths: - /users: - get: - operationId: listUsers - tags: - - users - responses: - "200": - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - /pets: - get: - operationId: listPets - tags: - - pets - responses: - "200": - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - /admin/settings: - get: - operationId: getSettings - tags: - - admin - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Settings' - put: - operationId: updateSettings - tags: - - admin - responses: - "200": - description: OK -components: - schemas: - User: - type: object - properties: - name: - type: string - Pet: - type: object - properties: - name: - type: string - Settings: - type: object - properties: - theme: - type: string -` - -func gatherTestOps(t *testing.T) []*OperationDescriptor { - t.Helper() - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - tracker := NewParamUsageTracker() - ops, err := GatherOperations(doc, tracker) - require.NoError(t, err) - return ops -} - -func opIDs(ops []*OperationDescriptor) []string { - ids := make([]string, len(ops)) - for i, op := range ops { - ids[i] = op.OperationID - } - return ids -} - -func TestFilterOperationsByTag_Include(t *testing.T) { - ops := gatherTestOps(t) - require.Len(t, ops, 4) - - filtered := FilterOperationsByTag(ops, OutputOptions{ - IncludeTags: []string{"users"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "listUsers") - assert.NotContains(t, ids, "listPets") - assert.NotContains(t, ids, "getSettings") - assert.NotContains(t, ids, "updateSettings") -} - -func TestFilterOperationsByTag_Exclude(t *testing.T) { - ops := gatherTestOps(t) - - filtered := FilterOperationsByTag(ops, OutputOptions{ - ExcludeTags: []string{"admin"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "listUsers") - assert.Contains(t, ids, "listPets") - assert.NotContains(t, ids, "getSettings") - assert.NotContains(t, ids, "updateSettings") -} - -func TestFilterOperationsByTag_IncludeMultiple(t *testing.T) { - ops := gatherTestOps(t) - - filtered := FilterOperationsByTag(ops, OutputOptions{ - IncludeTags: []string{"users", "pets"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "listUsers") - assert.Contains(t, ids, "listPets") - assert.NotContains(t, ids, "getSettings") - assert.Len(t, filtered, 2) -} - -func TestFilterOperationsByTag_Empty(t *testing.T) { - ops := gatherTestOps(t) - - filtered := FilterOperationsByTag(ops, OutputOptions{}) - assert.Len(t, filtered, 4) -} - -func TestFilterOperationsByOperationID_Include(t *testing.T) { - ops := gatherTestOps(t) - - filtered := FilterOperationsByOperationID(ops, OutputOptions{ - IncludeOperationIDs: []string{"listPets"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "listPets") - assert.Len(t, filtered, 1) -} - -func TestFilterOperationsByOperationID_Exclude(t *testing.T) { - ops := gatherTestOps(t) - - filtered := FilterOperationsByOperationID(ops, OutputOptions{ - ExcludeOperationIDs: []string{"getSettings", "updateSettings"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "listUsers") - assert.Contains(t, ids, "listPets") - assert.NotContains(t, ids, "getSettings") - assert.NotContains(t, ids, "updateSettings") - assert.Len(t, filtered, 2) -} - -func TestFilterOperations_Combined(t *testing.T) { - ops := gatherTestOps(t) - - // Include only admin, then exclude updateSettings - filtered := FilterOperations(ops, OutputOptions{ - IncludeTags: []string{"admin"}, - ExcludeOperationIDs: []string{"updateSettings"}, - }) - - ids := opIDs(filtered) - assert.Contains(t, ids, "getSettings") - assert.NotContains(t, ids, "updateSettings") - assert.Len(t, filtered, 1) -} - -func TestFilterSchemasByName(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - matcher := NewContentTypeMatcher(DefaultContentTypes()) - schemas, err := GatherSchemas(doc, matcher) - require.NoError(t, err) - - // Count component schemas - var componentNames []string - for _, s := range schemas { - if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { - componentNames = append(componentNames, s.Path[2]) - } - } - assert.Contains(t, componentNames, "User") - assert.Contains(t, componentNames, "Pet") - assert.Contains(t, componentNames, "Settings") - - // Exclude Pet - filtered := FilterSchemasByName(schemas, []string{"Pet"}) - - var filteredNames []string - for _, s := range filtered { - if len(s.Path) == 3 && s.Path[0] == "components" && s.Path[1] == "schemas" { - filteredNames = append(filteredNames, s.Path[2]) - } - } - assert.Contains(t, filteredNames, "User") - assert.NotContains(t, filteredNames, "Pet") - assert.Contains(t, filteredNames, "Settings") -} - -func TestFilterSchemasByName_Empty(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - matcher := NewContentTypeMatcher(DefaultContentTypes()) - schemas, err := GatherSchemas(doc, matcher) - require.NoError(t, err) - - filtered := FilterSchemasByName(schemas, nil) - assert.Equal(t, len(schemas), len(filtered)) -} - -func TestFilterIntegration_GenerateWithIncludeTags(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - Generation: GenerationOptions{ - Client: true, - }, - OutputOptions: OutputOptions{ - IncludeTags: []string{"users"}, - }, - } - - code, err := Generate(doc, []byte(filterTestSpec), cfg) - require.NoError(t, err) - // Client interface should only contain the included operation - assert.Contains(t, code, "ListUsers(ctx context.Context") - assert.NotContains(t, code, "ListPets(ctx context.Context") - assert.NotContains(t, code, "GetSettings(ctx context.Context") -} - -func TestFilterIntegration_GenerateWithExcludeTags(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - Generation: GenerationOptions{ - Client: true, - }, - OutputOptions: OutputOptions{ - ExcludeTags: []string{"admin"}, - }, - } - - code, err := Generate(doc, []byte(filterTestSpec), cfg) - require.NoError(t, err) - // Client interface should include users and pets but not admin operations - assert.Contains(t, code, "ListUsers(ctx context.Context") - assert.Contains(t, code, "ListPets(ctx context.Context") - assert.NotContains(t, code, "GetSettings(ctx context.Context") - assert.NotContains(t, code, "UpdateSettings(ctx context.Context") -} - -func TestFilterIntegration_GenerateWithExcludeSchemas(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - OutputOptions: OutputOptions{ - ExcludeSchemas: []string{"Pet"}, - }, - } - - code, err := Generate(doc, []byte(filterTestSpec), cfg) - require.NoError(t, err) - // User and Settings types should still exist - assert.Contains(t, code, "type User struct") - assert.Contains(t, code, "type Settings struct") - // Pet type should be excluded - assert.NotContains(t, code, "type Pet struct") -} - -func TestFilterIntegration_ServerWithIncludeTags(t *testing.T) { - doc, err := libopenapi.NewDocument([]byte(filterTestSpec)) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - Generation: GenerationOptions{ - Server: ServerTypeStdHTTP, - }, - OutputOptions: OutputOptions{ - IncludeTags: []string{"pets"}, - }, - } - - code, err := Generate(doc, []byte(filterTestSpec), cfg) - require.NoError(t, err) - // Server interface should only contain the included operation - assert.Contains(t, code, "ListPets(w http.ResponseWriter") - assert.NotContains(t, code, "ListUsers(w http.ResponseWriter") - assert.NotContains(t, code, "GetSettings(w http.ResponseWriter") -} From b097c1da068826d5e52be94c3b78f920e2758af6 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 7 Feb 2026 09:02:53 +0000 Subject: [PATCH 156/293] Revert "fix(deps): update module github.com/go-chi/chi/v5 to v5.2.2 [security] (#2198)" This reverts commit 98e5d1a848441a135ed4addd4934329b2309e81f. --- experimental/examples/petstore-expanded/chi/go.mod | 2 +- experimental/examples/petstore-expanded/chi/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/examples/petstore-expanded/chi/go.mod b/experimental/examples/petstore-expanded/chi/go.mod index 58fa2448db..3c9d10741e 100644 --- a/experimental/examples/petstore-expanded/chi/go.mod +++ b/experimental/examples/petstore-expanded/chi/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expan go 1.24.0 require ( - github.com/go-chi/chi/v5 v5.2.2 + github.com/go-chi/chi/v5 v5.2.0 github.com/google/uuid v1.6.0 github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 ) diff --git a/experimental/examples/petstore-expanded/chi/go.sum b/experimental/examples/petstore-expanded/chi/go.sum index 54ce010d7c..ad495c8907 100644 --- a/experimental/examples/petstore-expanded/chi/go.sum +++ b/experimental/examples/petstore-expanded/chi/go.sum @@ -1,4 +1,4 @@ -github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= -github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= +github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 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= From b0f22a0006d36ded82373df14b8ec27bd2f3e57f Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 7 Feb 2026 09:02:54 +0000 Subject: [PATCH 157/293] Revert "OpenAPI v3.1 support, experimental re-implementation using libopenapi (#2197)" This reverts commit 5206145c6c6fec742fcdb10d3caa2042a95baf2d. --- Makefile | 12 +- README.md | 4 +- experimental/Configuration.md | 246 -- experimental/Makefile | 35 - experimental/README.md | 164 -- experimental/cmd/oapi-codegen/main.go | 105 - experimental/examples/callback/client/main.go | 144 -- experimental/examples/callback/config.yaml | 6 - experimental/examples/callback/doc.go | 13 - experimental/examples/callback/server/main.go | 116 - experimental/examples/callback/tree-farm.yaml | 138 -- .../examples/callback/treefarm.gen.go | 503 ---- .../examples/petstore-expanded/chi/Makefile | 35 - .../examples/petstore-expanded/chi/go.mod | 11 - .../examples/petstore-expanded/chi/go.sum | 4 - .../examples/petstore-expanded/chi/main.go | 40 - .../petstore-expanded/chi/server/petstore.go | 135 -- .../chi/server/server.config.yaml | 6 - .../chi/server/server.gen.go | 1039 -------- .../client/client.config.yaml | 8 - .../petstore-expanded/client/client.gen.go | 1225 ---------- .../petstore-expanded/client/client_test.go | 161 -- .../client/validator/main.go | 143 -- .../examples/petstore-expanded/doc.go | 2 - .../petstore-expanded/echo-v4/Makefile | 35 - .../examples/petstore-expanded/echo-v4/go.mod | 23 - .../examples/petstore-expanded/echo-v4/go.sum | 33 - .../petstore-expanded/echo-v4/main.go | 34 - .../echo-v4/server/petstore.go | 123 - .../echo-v4/server/server.config.yaml | 6 - .../echo-v4/server/server.gen.go | 976 -------- .../examples/petstore-expanded/echo/Makefile | 35 - .../examples/petstore-expanded/echo/go.mod | 11 - .../examples/petstore-expanded/echo/go.sum | 16 - .../examples/petstore-expanded/echo/main.go | 34 - .../petstore-expanded/echo/server/petstore.go | 123 - .../echo/server/server.config.yaml | 6 - .../echo/server/server.gen.go | 977 -------- .../examples/petstore-expanded/fiber/Makefile | 35 - .../examples/petstore-expanded/fiber/go.mod | 31 - .../examples/petstore-expanded/fiber/go.sum | 51 - .../examples/petstore-expanded/fiber/main.go | 35 - .../fiber/server/petstore.go | 122 - .../fiber/server/server.config.yaml | 6 - .../fiber/server/server.gen.go | 969 -------- .../examples/petstore-expanded/generate.go | 11 - .../examples/petstore-expanded/gin/Makefile | 35 - .../examples/petstore-expanded/gin/go.mod | 40 - .../examples/petstore-expanded/gin/go.sum | 92 - .../examples/petstore-expanded/gin/main.go | 40 - .../petstore-expanded/gin/server/petstore.go | 126 - .../gin/server/server.config.yaml | 6 - .../gin/server/server.gen.go | 1007 -------- .../petstore-expanded/gorilla/Makefile | 35 - .../examples/petstore-expanded/gorilla/go.mod | 11 - .../examples/petstore-expanded/gorilla/go.sum | 4 - .../petstore-expanded/gorilla/main.go | 40 - .../gorilla/server/petstore.go | 135 -- .../gorilla/server/server.config.yaml | 6 - .../gorilla/server/server.gen.go | 1035 -------- .../examples/petstore-expanded/iris/Makefile | 35 - .../examples/petstore-expanded/iris/go.mod | 55 - .../examples/petstore-expanded/iris/go.sum | 178 -- .../examples/petstore-expanded/iris/main.go | 35 - .../petstore-expanded/iris/server/petstore.go | 130 - .../iris/server/server.config.yaml | 6 - .../iris/server/server.gen.go | 973 -------- .../petstore-expanded/models.config.yaml | 2 - .../petstore-expanded/petstore-expanded.yaml | 164 -- .../petstore-expanded/petstore.gen.go | 117 - .../petstore-expanded/stdhttp/Makefile | 35 - .../examples/petstore-expanded/stdhttp/go.mod | 7 - .../examples/petstore-expanded/stdhttp/go.sum | 2 - .../petstore-expanded/stdhttp/main.go | 39 - .../stdhttp/server/petstore.go | 163 -- .../stdhttp/server/server.config.yaml | 7 - .../stdhttp/server/server.gen.go | 1009 -------- experimental/examples/webhook/client/main.go | 150 -- experimental/examples/webhook/config.yaml | 6 - experimental/examples/webhook/doc.go | 13 - .../examples/webhook/door-badge-reader.yaml | 139 -- .../examples/webhook/doorbadge.gen.go | 1069 --------- experimental/examples/webhook/server/main.go | 186 -- experimental/go.mod | 27 - experimental/go.sum | 41 - experimental/internal/codegen/clientgen.go | 349 --- .../internal/codegen/clientgen_test.go | 188 -- experimental/internal/codegen/codegen.go | 1101 --------- .../internal/codegen/configuration.go | 317 --- .../internal/codegen/configuration_test.go | 152 -- experimental/internal/codegen/extension.go | 337 --- .../codegen/extension_integration_test.go | 201 -- .../internal/codegen/extension_test.go | 180 -- experimental/internal/codegen/gather.go | 621 ----- .../internal/codegen/gather_operations.go | 864 ------- experimental/internal/codegen/identifiers.go | 125 - .../internal/codegen/identifiers_test.go | 129 - experimental/internal/codegen/initiatorgen.go | 216 -- experimental/internal/codegen/inline.go | 92 - experimental/internal/codegen/inline_test.go | 139 -- experimental/internal/codegen/namemangling.go | 420 ---- .../internal/codegen/namemangling_test.go | 195 -- experimental/internal/codegen/operation.go | 287 --- experimental/internal/codegen/output.go | 764 ------ experimental/internal/codegen/paramgen.go | 178 -- .../internal/codegen/paramgen_test.go | 161 -- experimental/internal/codegen/receivergen.go | 131 - experimental/internal/codegen/schema.go | 117 - experimental/internal/codegen/schemanames.go | 812 ------- experimental/internal/codegen/servergen.go | 180 -- .../codegen/skip_external_ref_test.go | 68 - experimental/internal/codegen/structtags.go | 172 -- .../internal/codegen/templates/embed.go | 9 - .../templates/files/client/base.go.tmpl | 95 - .../templates/files/client/interface.go.tmpl | 17 - .../templates/files/client/methods.go.tmpl | 40 - .../files/client/request_builders.go.tmpl | 177 -- .../templates/files/client/simple.go.tmpl | 121 - .../templates/files/initiator/base.go.tmpl | 73 - .../files/initiator/interface.go.tmpl | 17 - .../templates/files/initiator/methods.go.tmpl | 41 - .../files/initiator/request_builders.go.tmpl | 149 -- .../templates/files/initiator/simple.go.tmpl | 121 - .../files/params/bind_deep_object.go.tmpl | 271 --- .../templates/files/params/bind_form.go.tmpl | 38 - .../files/params/bind_form_explode.go.tmpl | 145 -- .../templates/files/params/bind_label.go.tmpl | 46 - .../files/params/bind_label_explode.go.tmpl | 51 - .../files/params/bind_matrix.go.tmpl | 47 - .../files/params/bind_matrix_explode.go.tmpl | 65 - .../files/params/bind_pipe_delimited.go.tmpl | 33 - .../bind_pipe_delimited_explode.go.tmpl | 9 - .../files/params/bind_simple.go.tmpl | 38 - .../files/params/bind_simple_explode.go.tmpl | 38 - .../files/params/bind_space_delimited.go.tmpl | 33 - .../bind_space_delimited_explode.go.tmpl | 9 - .../templates/files/params/helpers.go.tmpl | 260 -- .../files/params/style_deep_object.go.tmpl | 74 - .../templates/files/params/style_form.go.tmpl | 132 -- .../files/params/style_form_explode.go.tmpl | 130 - .../files/params/style_label.go.tmpl | 129 - .../files/params/style_label_explode.go.tmpl | 129 - .../files/params/style_matrix.go.tmpl | 132 -- .../files/params/style_matrix_explode.go.tmpl | 130 - .../files/params/style_pipe_delimited.go.tmpl | 66 - .../style_pipe_delimited_explode.go.tmpl | 66 - .../files/params/style_simple.go.tmpl | 158 -- .../files/params/style_simple_explode.go.tmpl | 128 - .../params/style_space_delimited.go.tmpl | 66 - .../style_space_delimited_explode.go.tmpl | 66 - .../files/server/chi/handler.go.tmpl | 59 - .../files/server/chi/interface.go.tmpl | 24 - .../files/server/chi/receiver.go.tmpl | 95 - .../files/server/chi/wrapper.go.tmpl | 166 -- .../files/server/echo-v4/handler.go.tmpl | 34 - .../files/server/echo-v4/interface.go.tmpl | 24 - .../files/server/echo-v4/receiver.go.tmpl | 72 - .../files/server/echo-v4/wrapper.go.tmpl | 134 -- .../files/server/echo/handler.go.tmpl | 35 - .../files/server/echo/interface.go.tmpl | 24 - .../files/server/echo/receiver.go.tmpl | 72 - .../files/server/echo/wrapper.go.tmpl | 134 -- .../templates/files/server/errors.go.tmpl | 79 - .../files/server/fiber/handler.go.tmpl | 31 - .../files/server/fiber/interface.go.tmpl | 24 - .../files/server/fiber/receiver.go.tmpl | 71 - .../files/server/fiber/wrapper.go.tmpl | 137 -- .../files/server/gin/handler.go.tmpl | 37 - .../files/server/gin/interface.go.tmpl | 24 - .../files/server/gin/receiver.go.tmpl | 78 - .../files/server/gin/wrapper.go.tmpl | 161 -- .../files/server/gorilla/handler.go.tmpl | 57 - .../files/server/gorilla/interface.go.tmpl | 24 - .../files/server/gorilla/receiver.go.tmpl | 95 - .../files/server/gorilla/wrapper.go.tmpl | 169 -- .../files/server/iris/handler.go.tmpl | 28 - .../files/server/iris/interface.go.tmpl | 24 - .../files/server/iris/receiver.go.tmpl | 84 - .../files/server/iris/wrapper.go.tmpl | 160 -- .../files/server/param_types.go.tmpl | 24 - .../files/server/stdhttp/handler.go.tmpl | 63 - .../files/server/stdhttp/interface.go.tmpl | 13 - .../files/server/stdhttp/receiver.go.tmpl | 108 - .../files/server/stdhttp/wrapper.go.tmpl | 166 -- .../codegen/templates/files/types/date.tmpl | 38 - .../codegen/templates/files/types/email.tmpl | 43 - .../codegen/templates/files/types/file.tmpl | 64 - .../templates/files/types/nullable.tmpl | 104 - .../codegen/templates/files/types/uuid.tmpl | 3 - .../internal/codegen/templates/funcs.go | 151 -- .../internal/codegen/templates/registry.go | 909 ------- .../codegen/templates/test/types/date.gen.go | 46 - .../codegen/templates/test/types/date_test.go | 65 - .../codegen/templates/test/types/email.gen.go | 52 - .../templates/test/types/email_test.go | 176 -- .../codegen/templates/test/types/file.gen.go | 74 - .../codegen/templates/test/types/file_test.go | 54 - .../codegen/templates/test/types/generate.go | 3 - .../templates/test/types/gentypes/main.go | 109 - .../codegen/templates/test/types/uuid.gen.go | 10 - .../codegen/templates/test/types/uuid_test.go | 53 - .../codegen/test/comprehensive/doc.go | 3 - .../comprehensive/output/comprehensive.gen.go | 2098 ----------------- .../test/default_values/default_values.yaml | 158 -- .../output/default_values.gen.go | 514 ---- .../output/default_values_test.go | 324 --- .../codegen/test/external_ref/config.yaml | 5 - .../test/external_ref/external_ref_test.go | 62 - .../test/external_ref/packagea/config.yaml | 4 - .../test/external_ref/packagea/spec.gen.go | 22 - .../test/external_ref/packagea/spec.yaml | 14 - .../test/external_ref/packageb/config.yaml | 2 - .../test/external_ref/packageb/spec.gen.go | 14 - .../test/external_ref/packageb/spec.yaml | 12 - .../codegen/test/external_ref/spec.gen.go | 26 - .../codegen/test/external_ref/spec.yaml | 14 - .../codegen/test/files/comprehensive.yaml | 861 ------- .../codegen/test/issues/issue_1029/doc.go | 5 - .../issues/issue_1029/output/types.gen.go | 186 -- .../issues/issue_1029/output/types_test.go | 89 - .../codegen/test/issues/issue_1029/spec.yaml | 29 - .../codegen/test/issues/issue_1039/doc.go | 5 - .../issues/issue_1039/output/types.gen.go | 291 --- .../issues/issue_1039/output/types_test.go | 266 --- .../codegen/test/issues/issue_1039/spec.yaml | 86 - .../codegen/test/issues/issue_1397/doc.go | 5 - .../issues/issue_1397/output/types.gen.go | 114 - .../issues/issue_1397/output/types_test.go | 81 - .../codegen/test/issues/issue_1397/spec.yaml | 57 - .../codegen/test/issues/issue_1429/doc.go | 5 - .../issues/issue_1429/output/types.gen.go | 149 -- .../issues/issue_1429/output/types_test.go | 37 - .../codegen/test/issues/issue_1429/spec.yaml | 33 - .../codegen/test/issues/issue_1496/doc.go | 5 - .../issues/issue_1496/output/types.gen.go | 168 -- .../issues/issue_1496/output/types_test.go | 41 - .../codegen/test/issues/issue_1496/spec.yaml | 40 - .../codegen/test/issues/issue_1710/doc.go | 5 - .../issues/issue_1710/output/types.gen.go | 212 -- .../issues/issue_1710/output/types_test.go | 102 - .../codegen/test/issues/issue_1710/spec.yaml | 76 - .../codegen/test/issues/issue_193/doc.go | 5 - .../test/issues/issue_193/output/types.gen.go | 71 - .../issues/issue_193/output/types_test.go | 76 - .../codegen/test/issues/issue_193/spec.yaml | 27 - .../codegen/test/issues/issue_2102/doc.go | 5 - .../issues/issue_2102/output/types.gen.go | 82 - .../issues/issue_2102/output/types_test.go | 52 - .../codegen/test/issues/issue_2102/spec.yaml | 39 - .../codegen/test/issues/issue_312/doc.go | 6 - .../test/issues/issue_312/output/types.gen.go | 97 - .../issues/issue_312/output/types_test.go | 72 - .../codegen/test/issues/issue_312/spec.yaml | 86 - .../codegen/test/issues/issue_502/doc.go | 5 - .../test/issues/issue_502/output/types.gen.go | 228 -- .../issues/issue_502/output/types_test.go | 107 - .../codegen/test/issues/issue_502/spec.yaml | 29 - .../codegen/test/issues/issue_52/doc.go | 5 - .../test/issues/issue_52/output/types.gen.go | 87 - .../test/issues/issue_52/output/types_test.go | 64 - .../codegen/test/issues/issue_52/spec.yaml | 41 - .../codegen/test/issues/issue_579/doc.go | 5 - .../test/issues/issue_579/output/types.gen.go | 110 - .../issues/issue_579/output/types_test.go | 64 - .../codegen/test/issues/issue_579/spec.yaml | 30 - .../codegen/test/issues/issue_697/doc.go | 5 - .../test/issues/issue_697/output/types.gen.go | 81 - .../issues/issue_697/output/types_test.go | 58 - .../codegen/test/issues/issue_697/spec.yaml | 27 - .../codegen/test/issues/issue_775/doc.go | 5 - .../test/issues/issue_775/output/types.gen.go | 86 - .../issues/issue_775/output/types_test.go | 37 - .../codegen/test/issues/issue_775/spec.yaml | 22 - .../codegen/test/issues/issue_832/doc.go | 5 - .../test/issues/issue_832/output/types.gen.go | 91 - .../issues/issue_832/output/types_test.go | 62 - .../codegen/test/issues/issue_832/spec.yaml | 45 - .../issue_head_digit_operation_id/doc.go | 5 - .../output/types.gen.go | 69 - .../output/types_test.go | 50 - .../issue_head_digit_operation_id/spec.yaml | 20 - .../issues/issue_illegal_enum_names/doc.go | 5 - .../output/types.gen.go | 80 - .../output/types_test.go | 51 - .../issues/issue_illegal_enum_names/spec.yaml | 37 - .../codegen/test/nested_aggregate/doc.go | 3 - .../nested_aggregate/nested_aggregate.yaml | 62 - .../output/nested_aggregate.gen.go | 400 ---- .../output/nested_aggregate_test.go | 332 --- experimental/internal/codegen/typegen.go | 918 -------- experimental/internal/codegen/typemapping.go | 98 - experimental/internal/codegen/typenames.go | 1 - scripts/foreach-module.sh | 20 - 293 files changed, 7 insertions(+), 41797 deletions(-) delete mode 100644 experimental/Configuration.md delete mode 100644 experimental/Makefile delete mode 100644 experimental/README.md delete mode 100644 experimental/cmd/oapi-codegen/main.go delete mode 100644 experimental/examples/callback/client/main.go delete mode 100644 experimental/examples/callback/config.yaml delete mode 100644 experimental/examples/callback/doc.go delete mode 100644 experimental/examples/callback/server/main.go delete mode 100644 experimental/examples/callback/tree-farm.yaml delete mode 100644 experimental/examples/callback/treefarm.gen.go delete mode 100644 experimental/examples/petstore-expanded/chi/Makefile delete mode 100644 experimental/examples/petstore-expanded/chi/go.mod delete mode 100644 experimental/examples/petstore-expanded/chi/go.sum delete mode 100644 experimental/examples/petstore-expanded/chi/main.go delete mode 100644 experimental/examples/petstore-expanded/chi/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/chi/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/chi/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/client/client.config.yaml delete mode 100644 experimental/examples/petstore-expanded/client/client.gen.go delete mode 100644 experimental/examples/petstore-expanded/client/client_test.go delete mode 100644 experimental/examples/petstore-expanded/client/validator/main.go delete mode 100644 experimental/examples/petstore-expanded/doc.go delete mode 100644 experimental/examples/petstore-expanded/echo-v4/Makefile delete mode 100644 experimental/examples/petstore-expanded/echo-v4/go.mod delete mode 100644 experimental/examples/petstore-expanded/echo-v4/go.sum delete mode 100644 experimental/examples/petstore-expanded/echo-v4/main.go delete mode 100644 experimental/examples/petstore-expanded/echo-v4/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/echo-v4/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/echo/Makefile delete mode 100644 experimental/examples/petstore-expanded/echo/go.mod delete mode 100644 experimental/examples/petstore-expanded/echo/go.sum delete mode 100644 experimental/examples/petstore-expanded/echo/main.go delete mode 100644 experimental/examples/petstore-expanded/echo/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/echo/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/echo/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/fiber/Makefile delete mode 100644 experimental/examples/petstore-expanded/fiber/go.mod delete mode 100644 experimental/examples/petstore-expanded/fiber/go.sum delete mode 100644 experimental/examples/petstore-expanded/fiber/main.go delete mode 100644 experimental/examples/petstore-expanded/fiber/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/fiber/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/fiber/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/generate.go delete mode 100644 experimental/examples/petstore-expanded/gin/Makefile delete mode 100644 experimental/examples/petstore-expanded/gin/go.mod delete mode 100644 experimental/examples/petstore-expanded/gin/go.sum delete mode 100644 experimental/examples/petstore-expanded/gin/main.go delete mode 100644 experimental/examples/petstore-expanded/gin/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/gin/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/gin/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/gorilla/Makefile delete mode 100644 experimental/examples/petstore-expanded/gorilla/go.mod delete mode 100644 experimental/examples/petstore-expanded/gorilla/go.sum delete mode 100644 experimental/examples/petstore-expanded/gorilla/main.go delete mode 100644 experimental/examples/petstore-expanded/gorilla/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/gorilla/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/gorilla/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/iris/Makefile delete mode 100644 experimental/examples/petstore-expanded/iris/go.mod delete mode 100644 experimental/examples/petstore-expanded/iris/go.sum delete mode 100644 experimental/examples/petstore-expanded/iris/main.go delete mode 100644 experimental/examples/petstore-expanded/iris/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/iris/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/iris/server/server.gen.go delete mode 100644 experimental/examples/petstore-expanded/models.config.yaml delete mode 100644 experimental/examples/petstore-expanded/petstore-expanded.yaml delete mode 100644 experimental/examples/petstore-expanded/petstore.gen.go delete mode 100644 experimental/examples/petstore-expanded/stdhttp/Makefile delete mode 100644 experimental/examples/petstore-expanded/stdhttp/go.mod delete mode 100644 experimental/examples/petstore-expanded/stdhttp/go.sum delete mode 100644 experimental/examples/petstore-expanded/stdhttp/main.go delete mode 100644 experimental/examples/petstore-expanded/stdhttp/server/petstore.go delete mode 100644 experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml delete mode 100644 experimental/examples/petstore-expanded/stdhttp/server/server.gen.go delete mode 100644 experimental/examples/webhook/client/main.go delete mode 100644 experimental/examples/webhook/config.yaml delete mode 100644 experimental/examples/webhook/doc.go delete mode 100644 experimental/examples/webhook/door-badge-reader.yaml delete mode 100644 experimental/examples/webhook/doorbadge.gen.go delete mode 100644 experimental/examples/webhook/server/main.go delete mode 100644 experimental/go.mod delete mode 100644 experimental/go.sum delete mode 100644 experimental/internal/codegen/clientgen.go delete mode 100644 experimental/internal/codegen/clientgen_test.go delete mode 100644 experimental/internal/codegen/codegen.go delete mode 100644 experimental/internal/codegen/configuration.go delete mode 100644 experimental/internal/codegen/configuration_test.go delete mode 100644 experimental/internal/codegen/extension.go delete mode 100644 experimental/internal/codegen/extension_integration_test.go delete mode 100644 experimental/internal/codegen/extension_test.go delete mode 100644 experimental/internal/codegen/gather.go delete mode 100644 experimental/internal/codegen/gather_operations.go delete mode 100644 experimental/internal/codegen/identifiers.go delete mode 100644 experimental/internal/codegen/identifiers_test.go delete mode 100644 experimental/internal/codegen/initiatorgen.go delete mode 100644 experimental/internal/codegen/inline.go delete mode 100644 experimental/internal/codegen/inline_test.go delete mode 100644 experimental/internal/codegen/namemangling.go delete mode 100644 experimental/internal/codegen/namemangling_test.go delete mode 100644 experimental/internal/codegen/operation.go delete mode 100644 experimental/internal/codegen/output.go delete mode 100644 experimental/internal/codegen/paramgen.go delete mode 100644 experimental/internal/codegen/paramgen_test.go delete mode 100644 experimental/internal/codegen/receivergen.go delete mode 100644 experimental/internal/codegen/schema.go delete mode 100644 experimental/internal/codegen/schemanames.go delete mode 100644 experimental/internal/codegen/servergen.go delete mode 100644 experimental/internal/codegen/skip_external_ref_test.go delete mode 100644 experimental/internal/codegen/structtags.go delete mode 100644 experimental/internal/codegen/templates/embed.go delete mode 100644 experimental/internal/codegen/templates/files/client/base.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/client/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/client/methods.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/client/request_builders.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/client/simple.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/initiator/base.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/initiator/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/initiator/methods.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/initiator/simple.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_form.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_label.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/helpers.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_form.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_label.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_simple.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/errors.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/param_types.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl delete mode 100644 experimental/internal/codegen/templates/files/types/date.tmpl delete mode 100644 experimental/internal/codegen/templates/files/types/email.tmpl delete mode 100644 experimental/internal/codegen/templates/files/types/file.tmpl delete mode 100644 experimental/internal/codegen/templates/files/types/nullable.tmpl delete mode 100644 experimental/internal/codegen/templates/files/types/uuid.tmpl delete mode 100644 experimental/internal/codegen/templates/funcs.go delete mode 100644 experimental/internal/codegen/templates/registry.go delete mode 100644 experimental/internal/codegen/templates/test/types/date.gen.go delete mode 100644 experimental/internal/codegen/templates/test/types/date_test.go delete mode 100644 experimental/internal/codegen/templates/test/types/email.gen.go delete mode 100644 experimental/internal/codegen/templates/test/types/email_test.go delete mode 100644 experimental/internal/codegen/templates/test/types/file.gen.go delete mode 100644 experimental/internal/codegen/templates/test/types/file_test.go delete mode 100644 experimental/internal/codegen/templates/test/types/generate.go delete mode 100644 experimental/internal/codegen/templates/test/types/gentypes/main.go delete mode 100644 experimental/internal/codegen/templates/test/types/uuid.gen.go delete mode 100644 experimental/internal/codegen/templates/test/types/uuid_test.go delete mode 100644 experimental/internal/codegen/test/comprehensive/doc.go delete mode 100644 experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go delete mode 100644 experimental/internal/codegen/test/default_values/default_values.yaml delete mode 100644 experimental/internal/codegen/test/default_values/output/default_values.gen.go delete mode 100644 experimental/internal/codegen/test/default_values/output/default_values_test.go delete mode 100644 experimental/internal/codegen/test/external_ref/config.yaml delete mode 100644 experimental/internal/codegen/test/external_ref/external_ref_test.go delete mode 100644 experimental/internal/codegen/test/external_ref/packagea/config.yaml delete mode 100644 experimental/internal/codegen/test/external_ref/packagea/spec.gen.go delete mode 100644 experimental/internal/codegen/test/external_ref/packagea/spec.yaml delete mode 100644 experimental/internal/codegen/test/external_ref/packageb/config.yaml delete mode 100644 experimental/internal/codegen/test/external_ref/packageb/spec.gen.go delete mode 100644 experimental/internal/codegen/test/external_ref/packageb/spec.yaml delete mode 100644 experimental/internal/codegen/test/external_ref/spec.gen.go delete mode 100644 experimental/internal/codegen/test/external_ref/spec.yaml delete mode 100644 experimental/internal/codegen/test/files/comprehensive.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1029/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1029/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1029/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1039/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1039/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1039/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1397/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1397/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1397/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1429/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1429/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1429/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1496/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1496/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1496/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_1710/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1710/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_1710/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_193/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_193/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_193/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_193/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_2102/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_2102/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_2102/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_312/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_312/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_312/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_312/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_502/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_502/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_502/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_502/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_52/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_52/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_52/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_52/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_579/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_579/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_579/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_579/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_697/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_697/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_697/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_697/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_775/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_775/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_775/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_775/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_832/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_832/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_832/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_832/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml delete mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go delete mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go delete mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go delete mode 100644 experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml delete mode 100644 experimental/internal/codegen/test/nested_aggregate/doc.go delete mode 100644 experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml delete mode 100644 experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go delete mode 100644 experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go delete mode 100644 experimental/internal/codegen/typegen.go delete mode 100644 experimental/internal/codegen/typemapping.go delete mode 100644 experimental/internal/codegen/typenames.go delete mode 100755 scripts/foreach-module.sh diff --git a/Makefile b/Makefile index 89b6de0f6d..069527cf0e 100644 --- a/Makefile +++ b/Makefile @@ -19,34 +19,34 @@ lint: tools # run the root module explicitly, to prevent recursive calls by re-invoking `make ...` top-level $(GOBIN)/golangci-lint run ./... # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint' lint-ci: tools # for the root module, explicitly run the step, to prevent recursive calls $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint-ci + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint-ci' generate: # for the root module, explicitly run the step, to prevent recursive calls go generate ./... # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh generate + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make generate' test: # for the root module, explicitly run the step, to prevent recursive calls go test -cover ./... # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh test + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make test' tidy: # for the root module, explicitly run the step, to prevent recursive calls go mod tidy # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy' tidy-ci: # for the root module, explicitly run the step, to prevent recursive calls tidied -verbose # then, for all child modules, use a module-managed `Makefile` - GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy-ci + git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy-ci' diff --git a/README.md b/README.md index ecf9a55e66..7bac0d2e98 100644 --- a/README.md +++ b/README.md @@ -393,9 +393,7 @@ 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 in experimental form, as a complete rewrite using [libopenapi](https://github.com/pb33f/libopenapi). Please look in the - `./experimental` directory. This is potentially the future V3 of `oapi-codegen` and is functionally complete, just not deeply tested yet. Many OpenAPI 3.1 - features are supported, such as webhooks and callbacks. + - OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373) - 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)) diff --git a/experimental/Configuration.md b/experimental/Configuration.md deleted file mode 100644 index 55f550e2f3..0000000000 --- a/experimental/Configuration.md +++ /dev/null @@ -1,246 +0,0 @@ -# Configuration Reference - -`oapi-codegen` is configured using a YAML file. All sections are optional — you only need to include what you want to change from the defaults. - -Below is a fully annotated configuration file showing every option. - -```yaml -# The Go package name for generated code. -# Can also be set with -package flag. -package: myapi - -# Output file path. -# Can also be set with -output flag. -# Default: .gen.go -output: types.gen.go - -# Generation controls which parts of the code are generated. -generation: - # Server framework to generate code for. - # Supported: "std-http", "chi", "echo", "echo/v4", "gin", "gorilla", "fiber", "iris" - # Default: "" (no server code generated) - server: std-http - - # Generate an HTTP client that returns *http.Response. - # Default: false - client: true - - # Generate a SimpleClient wrapper with typed responses. - # Requires client: true. - # Default: false - simple-client: true - - # Use model types from an external package instead of generating them locally. - # When set, models are imported rather than generated. - # Default: not set (models are generated locally) - models-package: - path: github.com/org/project/models - alias: models # optional, defaults to last segment of path - -# Type mappings: OpenAPI type/format to Go type. -# User values are merged on top of defaults — you only need to specify overrides. -type-mapping: - integer: - default: - type: int # default - formats: - int32: - type: int32 # default - int64: - type: int64 # default - number: - default: - type: float32 # default - formats: - double: - type: float64 # default - boolean: - default: - type: bool # default - string: - default: - type: string # default - formats: - byte: - type: "[]byte" # default - date: - type: Date # default, custom template type - date-time: - type: time.Time # default - import: time - uuid: - type: UUID # default, custom template type - email: - type: Email # default, custom template type - binary: - type: File # default, custom template type - json: - type: json.RawMessage # default - import: encoding/json - # Add your own format mappings: - money: - type: decimal.Decimal - import: github.com/shopspring/decimal - -# Name mangling: controls how OpenAPI names become Go identifiers. -# User values are merged on top of defaults. -name-mangling: - # Prefix prepended when a name starts with a digit. - # Default: "N" (e.g., "123foo" becomes "N123foo") - numeric-prefix: "N" - - # Prefix prepended when a name conflicts with a Go keyword. - # Default: "" (uses keyword-suffix instead) - keyword-prefix: "" - - # Characters that mark word boundaries (next letter is capitalised). - # Default includes most punctuation: - # @ ! $ & = . + : ; _ ~ space ( ) { } [ ] | < > ? / \ - word-separators: "-#@!$&=.+:;_~ (){}[]|<>?/\\" - - # Words that should remain all-uppercase. - initialisms: - - ACL - - API - - ASCII - - CPU - - CSS - - DB - - DNS - - EOF - - GUID - - HTML - - HTTP - - HTTPS - - ID - - IP - - JSON - - QPS - - RAM - - RPC - - SLA - - SMTP - - SQL - - SSH - - TCP - - TLS - - TTL - - UDP - - UI - - UID - - GID - - URI - - URL - - UTF8 - - UUID - - VM - - XML - - XMPP - - XSRF - - XSS - - SIP - - RTP - - AMQP - - TS - - # Characters that get replaced with words when they appear at the start of a name. - character-substitutions: - "$": DollarSign - "-": Minus - "+": Plus - "&": And - "|": Or - "~": Tilde - "=": Equal - ">": GreaterThan - "<": LessThan - "#": Hash - ".": Dot - "*": Asterisk - "^": Caret - "%": Percent - "_": Underscore - "@": At - "!": Bang - "?": Question - "/": Slash - "\\": Backslash - ":": Colon - ";": Semicolon - "'": Apos - "\"": Quote - "`": Backtick - "(": LParen - ")": RParen - "[": LBracket - "]": RBracket - "{": LBrace - "}": RBrace - -# Name substitutions: direct overrides for specific generated names. -name-substitutions: - # Override type names during generation. - type-names: - foo: MyCustomFoo # Schema "foo" generates type "MyCustomFoo" instead of "Foo" - # Override property/field names during generation. - property-names: - bar: MyCustomBar # Property "bar" generates field "MyCustomBar" instead of "Bar" - -# Import mapping: resolve external $ref targets to Go packages. -# Required when your spec references schemas from other files. -import-mapping: - ../common/api.yaml: github.com/org/project/common - https://example.com/specs/shared.yaml: github.com/org/shared - # Use "-" to indicate types should stay in the current package - ./local-types.yaml: "-" - -# Content types: regexp patterns controlling which media types generate models. -# Only request/response bodies with matching content types will have types generated. -# Default: JSON types only. -content-types: - - "^application/json$" - - "^application/.*\\+json$" - # Add custom patterns as needed: - # - "^application/xml$" - # - "^text/plain$" - -# Content type short names: maps content type patterns to short names -# used in generated type names (e.g., "FindPetsJSONResponse"). -content-type-short-names: - - pattern: "^application/json$" - short-name: JSON - - pattern: "^application/xml$" - short-name: XML - - pattern: "^text/plain$" - short-name: Text - # ... defaults cover JSON, XML, Text, HTML, Binary, Multipart, Form - -# Struct tags: controls which struct tags are generated and their format. -# Uses Go text/template syntax. If specified, completely replaces the defaults. -# Default: json and form tags. -struct-tags: - tags: - - name: json - template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{if .OmitZero}},omitzero{{end}}{{end}}' - - name: form - template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{end}}' - # Add additional tags: - - name: yaml - template: '{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}' - - name: db - template: '{{ .FieldName }}' -``` - -## Struct tag template variables - -The struct tag templates have access to the following fields: - -| Variable | Type | Description | -|----------|------|-------------| -| `.FieldName` | `string` | The original field name from the OpenAPI spec | -| `.GoFieldName` | `string` | The Go identifier name after name mangling | -| `.IsOptional` | `bool` | Whether the field is optional in the schema | -| `.IsNullable` | `bool` | Whether the field is nullable | -| `.IsPointer` | `bool` | Whether the field is rendered as a pointer type | -| `.OmitEmpty` | `bool` | Whether `omitempty` should be applied (from extensions or optionality) | -| `.OmitZero` | `bool` | Whether `omitzero` should be applied (from `x-oapi-codegen-omitzero` extension) | -| `.JSONIgnore` | `bool` | Whether the field should be ignored in JSON (from `x-go-json-ignore` extension) | diff --git a/experimental/Makefile b/experimental/Makefile deleted file mode 100644 index a2ddf18fb1..0000000000 --- a/experimental/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - @echo "Skipping tests in experimental module" - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/README.md b/experimental/README.md deleted file mode 100644 index 4ce7d6310a..0000000000 --- a/experimental/README.md +++ /dev/null @@ -1,164 +0,0 @@ -# `oapi-codegen` V3 - -This is an experimental prototype of a V3 version of oapi-codegen. The generated code and command line options are not yet stable. Use at your -own risk. - -## What is new in Version 3 -This directory contains an experimental version of oapi-codegen's future V3 version, which is based on [libopenapi](https://github.com/pb33f/libopenapi), -instead of the prior [kin-openapi](https://github.com/getkin/kin-openapi). This change necessitated a nearly complete rewrite, but we strive to be as -compatible as possible. - -What is working: - - All model, client and server generation as in earlier versions. - - We have added Webhook and Callback support, please see `./examples`, which contains the ubiquitous OpenAPI pet shop implemented in all supported servers - and examples of webhooks and callbacks implemented on top of the `http.ServeMux` server, with no additional imports. - - Model generation of `allOf`, `anyOf`, `oneOf` is much more robust, since these were a source of many problems in earlier versions. - - Echo V5 support has been added (Go 1.25 required) - -What is missing: - - We have not yet created any runtime code like request validation middleware. - -## Differences in V3 - -V3 is a brand new implementation, and may (will) contain new bugs, but also strives to fix many current, existing bugs. We've run quite a few -conformance tests against specifications in old Issues, and we're looking pretty good! Please try this out, and if it failes in some way, please -file Issues. - -### Aggregate Schemas - -V3 implements `oneOf`, `anyOf`, `allOf` differently. Our prior versions had pretty good handling for `allOf`, where we merge all the constituent schemas -into a schema object that contains all the fields of the originals. It makes sense, since this is composition. - -`oneOf` and `anyOf` were handled by deferred parsing, where the JSON was captured into `json.RawMessage` and helper functions were created on each -type to parse the JSON as any constituent type with the user's help. - -Given the following schemas: - -```yaml -components: - schemas: - Cat: - type: object - properties: - name: - type: string - color: - type: string - Dog: - type: object - properties: - name: - type: string - color: - type: string - Fish: - type: object - properties: - species: - type: string - isSaltwater: - type: boolean - NamedPet: - anyOf: - - $ref: '#/components/schemas/Cat' - - $ref: '#/components/schemas/Dog' - SpecificPet: - oneOf: - - $ref: '#/components/schemas/Cat' - - $ref: '#/components/schemas/Dog' - - $ref: '#/components/schemas/Fish' -``` - -#### V2 output - -V2 generates both `NamedPet` (anyOf) and `SpecificPet` (oneOf) identically as opaque wrappers around `json.RawMessage`: - -```go -type NamedPet struct { - union json.RawMessage -} - -type SpecificPet struct { - union json.RawMessage -} -``` - -The actual variant types are invisible at the struct level. To access the underlying data, the user must call generated helper methods: - -```go -// NamedPet (anyOf) helpers -func (t NamedPet) AsCat() (Cat, error) -func (t *NamedPet) FromCat(v Cat) error -// - -// SpecificPet (oneOf) helpers - -func (t SpecificPet) AsFish() (Fish, error) -func (t *SpecificPet) FromFish(v Fish) error -func (t *SpecificPet) MergeFish(v Fish) error -// -``` - -Note that `anyOf` and `oneOf` produce identical types and method signatures; there is no semantic difference in the generated code. - -#### V3 output - -V3 generates structs with exported pointer fields for each variant, making the union members visible at the type level. Crucially, `anyOf` and `oneOf` now have different marshal/unmarshal semantics. - -**`anyOf` (NamedPet)** — `MarshalJSON` merges all non-nil variants into a single JSON object. `UnmarshalJSON` tries every variant and keeps whichever succeed: - -```go -type NamedPet struct { - Cat *Cat - Dog *Dog -} - -``` - -**`oneOf` (SpecificPet)** — `MarshalJSON` returns an error unless exactly one field is non-nil. `UnmarshalJSON` returns an error unless the JSON matches exactly one variant: - -```go -type SpecificPet struct { - Cat *Cat - Dog *Dog - Fish *Fish -} -``` - -### OpenAPI V3.1 Feature Support - -Thanks to [libopenapi](https://github.com/pb33f/libopenapi), we are able to parse OpenAPI 3.1 and 3.2 specifications. They are functionally similar, you can -read the differences between `nullable` fields yourself, but they add some new functionality, namely `webhooks` and `callbacks`. We support all of them in -this prototype. `callbacks` and `webhooks` are basically the inverse of `paths`. Webhooks contain no URL element in their definition, so we can't register handlers -for you in your http router of choice, you have to do that yourself. Callbacks support complex request URL's which may reference the original request. This is -something you need to pull out of the request body, and doing it generically is difficult, so we punt this problem, for now, to our users. - -Please see the [webhook example](examples/webhook/). It creates a little server that pretends to be a door badge reader, and it generates an event stream -about people coming and going. Any number of clients may subscribe to this event. See the [doc.go](examples/webhook/doc.go) for usage examples. - -The [callback example](examples/callback), creates a little server that pretends to plant trees. Each tree planting request contains a callback to be notified -when tree planting is complete. We invoke those in a random order via delays, and the client prints out callbacks as they happen. Please see [doc.go](examples/callback/doc.go) for usage. - -### Flexible Configuration - -oapi-codegen V3 tries to make no assumptions about which initialisms, struct tags, or name mangling that is correct for you. A very [flexible configuration file](Configuration.md) allows you to override anything. - - -### No runtime dependency - -V2 generated code relied on `github.com/oapi-codegen/runtime` for parameter binding and styling. This was a complaint from lots of people due to various -audit requirements. V3 embeds all necessary helper functions and helper types into the spec. There are no longer generic, parameterized functions that -handle arbitrary parameters, but rather very specific functions for each kind of parameter, and we call the correct little helper versus a generic -runtime helper. - - -## Installation - -Go 1.24 is required, install like so: - - go get -tool github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen@latest - -You can then run the code generator - - //go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen - diff --git a/experimental/cmd/oapi-codegen/main.go b/experimental/cmd/oapi-codegen/main.go deleted file mode 100644 index 24c5320c90..0000000000 --- a/experimental/cmd/oapi-codegen/main.go +++ /dev/null @@ -1,105 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/pb33f/libopenapi" - "github.com/pb33f/libopenapi/datamodel" - - "gopkg.in/yaml.v3" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen" -) - -func main() { - configPath := flag.String("config", "", "path to configuration file") - flagPackage := flag.String("package", "", "Go package name for generated code") - flagOutput := flag.String("output", "", "output file path (default: .gen.go)") - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options] \n\n", os.Args[0]) - fmt.Fprintf(os.Stderr, "Arguments:\n") - fmt.Fprintf(os.Stderr, " spec-path path to OpenAPI spec file\n\n") - fmt.Fprintf(os.Stderr, "Options:\n") - flag.PrintDefaults() - } - flag.Parse() - - if flag.NArg() != 1 { - flag.Usage() - os.Exit(1) - } - - specPath := flag.Arg(0) - - // Parse the OpenAPI spec - specData, err := os.ReadFile(specPath) - if err != nil { - fmt.Fprintf(os.Stderr, "error reading spec: %v\n", err) - os.Exit(1) - } - - // Configure libopenapi to skip resolving external references. - // We handle external $refs via import mappings — the referenced specs - // don't need to be fetched or parsed. See pb33f/libopenapi#519. - docConfig := datamodel.NewDocumentConfiguration() - docConfig.SkipExternalRefResolution = true - - doc, err := libopenapi.NewDocumentWithConfiguration(specData, docConfig) - if err != nil { - fmt.Fprintf(os.Stderr, "error parsing spec: %v\n", err) - os.Exit(1) - } - - // Parse config if provided, otherwise use empty config - var cfg codegen.Configuration - if *configPath != "" { - configData, err := os.ReadFile(*configPath) - if err != nil { - fmt.Fprintf(os.Stderr, "error reading config: %v\n", err) - os.Exit(1) - } - if err := yaml.Unmarshal(configData, &cfg); err != nil { - fmt.Fprintf(os.Stderr, "error parsing config: %v\n", err) - os.Exit(1) - } - } - - // Flags override config file values - if *flagPackage != "" { - cfg.PackageName = *flagPackage - } - if *flagOutput != "" { - cfg.Output = *flagOutput - } - - // Default output to .gen.go - if cfg.Output == "" { - base := filepath.Base(specPath) - ext := filepath.Ext(base) - cfg.Output = strings.TrimSuffix(base, ext) + ".gen.go" - } - - // Default package name from output file - if cfg.PackageName == "" { - cfg.PackageName = "api" - } - - // Generate code - code, err := codegen.Generate(doc, specData, cfg) - if err != nil { - fmt.Fprintf(os.Stderr, "error generating code: %v\n", err) - os.Exit(1) - } - - // Write output - if err := os.WriteFile(cfg.Output, []byte(code), 0644); err != nil { - fmt.Fprintf(os.Stderr, "error writing output: %v\n", err) - os.Exit(1) - } - - fmt.Printf("Generated %s\n", cfg.Output) -} diff --git a/experimental/examples/callback/client/main.go b/experimental/examples/callback/client/main.go deleted file mode 100644 index 9e618448a3..0000000000 --- a/experimental/examples/callback/client/main.go +++ /dev/null @@ -1,144 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "log" - "net" - "net/http" - "sync" - "sync/atomic" - - treefarm "github.com/oapi-codegen/oapi-codegen/experimental/examples/callback" -) - -// trees and cities for our planting requests -var treeKinds = []string{ - "oak", "maple", "pine", "birch", "willow", - "cedar", "elm", "ash", "cherry", "walnut", -} - -var cities = []string{ - "Providence", "Austin", "Denver", "Seattle", "Chicago", - "Boston", "Miami", "Nashville", "Savannah", "Mountain View", -} - -// CallbackReceiver implements treefarm.CallbackReceiverInterface. -type CallbackReceiver struct { - received atomic.Int32 - total int - done chan struct{} - once sync.Once - - mu sync.Mutex - ordinals map[string]int // UUID string -> 1-based planting order -} - -var _ treefarm.CallbackReceiverInterface = (*CallbackReceiver)(nil) - -func NewCallbackReceiver(total int) *CallbackReceiver { - return &CallbackReceiver{ - total: total, - done: make(chan struct{}), - ordinals: make(map[string]int), - } -} - -func (cr *CallbackReceiver) Register(id string, ordinal int) { - cr.mu.Lock() - cr.ordinals[id] = ordinal - cr.mu.Unlock() -} - -func (cr *CallbackReceiver) HandleTreePlantedCallback(w http.ResponseWriter, r *http.Request) { - var result treefarm.TreePlantingResult - if err := json.NewDecoder(r.Body).Decode(&result); err != nil { - log.Printf("Error decoding callback: %v", err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - cr.mu.Lock() - ordinal := cr.ordinals[result.ID.String()] - cr.mu.Unlock() - - n := cr.received.Add(1) - log.Printf("Callback %d/%d received: tree #%d success=%v", n, cr.total, ordinal, result.Success) - - w.WriteHeader(http.StatusOK) - - if int(n) >= cr.total { - cr.once.Do(func() { close(cr.done) }) - } -} - -func main() { - serverAddr := flag.String("server", "http://localhost:8080", "Tree farm server address") - flag.Parse() - - const numTrees = 10 - - // Start callback receiver on an ephemeral port. - receiver := NewCallbackReceiver(numTrees) - - mux := http.NewServeMux() - mux.Handle("/tree_callback", treefarm.TreePlantedCallbackHandler(receiver, nil)) - - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - log.Fatalf("Failed to listen: %v", err) - } - callbackPort := listener.Addr().(*net.TCPAddr).Port - callbackURL := fmt.Sprintf("http://localhost:%d/tree_callback", callbackPort) - log.Printf("Callback receiver listening on port %d", callbackPort) - - go func() { - if err := http.Serve(listener, mux); err != nil { - log.Printf("Callback server stopped: %v", err) - } - }() - - // Send 10 tree planting requests. - client := &http.Client{} - for i := range numTrees { - req := treefarm.TreePlantingRequest{ - Kind: treeKinds[i], - Location: cities[i], - CallbackURL: callbackURL, - } - - body, err := json.Marshal(req) - if err != nil { - log.Fatalf("Failed to marshal request: %v", err) - } - - resp, err := client.Post( - *serverAddr+"/api/plant_tree", - "application/json", - bytes.NewReader(body), - ) - if err != nil { - log.Fatalf("Failed to plant tree %d: %v", i+1, err) - } - - var accepted treefarm.TreeWithID - if err := json.NewDecoder(resp.Body).Decode(&accepted); err != nil { - _ = resp.Body.Close() - log.Fatalf("Failed to decode response: %v", err) - } - _ = resp.Body.Close() - - receiver.Register(accepted.ID.String(), i+1) - log.Printf("Planted tree %d/%d: id=%s kind=%q location=%q", - i+1, numTrees, accepted.ID, accepted.Kind, accepted.Location) - } - - log.Printf("All %d trees planted, waiting for callbacks...", numTrees) - - // Wait for all callbacks. - <-receiver.done - - log.Printf("All %d callbacks received, done!", numTrees) -} diff --git a/experimental/examples/callback/config.yaml b/experimental/examples/callback/config.yaml deleted file mode 100644 index 29392d1127..0000000000 --- a/experimental/examples/callback/config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: treefarm -output: treefarm.gen.go -generation: - callback-initiator: true - callback-receiver: true - server: std-http diff --git a/experimental/examples/callback/doc.go b/experimental/examples/callback/doc.go deleted file mode 100644 index c441b88a3a..0000000000 --- a/experimental/examples/callback/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config config.yaml tree-farm.yaml - -// Package treefarm provides an example of how to handle OpenAPI callbacks. -// We create a server which plants trees. The client asks the server to plant -// a tree and requests a callback when the planting is done. -// -// The server program will wait 1-5 seconds before notifying the client that a -// tree has been planted. -// -// You can run the example by running these two commands in parallel -// go run ./server --port 8080 -// go run ./client --server http://localhost:8080 -package treefarm diff --git a/experimental/examples/callback/server/main.go b/experimental/examples/callback/server/main.go deleted file mode 100644 index 4b255de3b6..0000000000 --- a/experimental/examples/callback/server/main.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "flag" - "log" - "math/rand/v2" - "net" - "net/http" - "time" - - "github.com/google/uuid" - - treefarm "github.com/oapi-codegen/oapi-codegen/experimental/examples/callback" -) - -// TreeFarm implements treefarm.ServerInterface. -type TreeFarm struct { - initiator *treefarm.CallbackInitiator -} - -var _ treefarm.ServerInterface = (*TreeFarm)(nil) - -func NewTreeFarm() *TreeFarm { - initiator, err := treefarm.NewCallbackInitiator() - if err != nil { - log.Fatalf("Failed to create callback initiator: %v", err) - } - return &TreeFarm{initiator: initiator} -} - -func sendError(w http.ResponseWriter, code int, message string) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(treefarm.Error{ - Code: int32(code), - Message: message, - }) -} - -func (tf *TreeFarm) PlantTree(w http.ResponseWriter, r *http.Request) { - log.Printf("Received PlantTree request from %s", r.RemoteAddr) - - var req treefarm.TreePlantingRequest - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - sendError(w, http.StatusBadRequest, "Invalid request body: "+err.Error()) - return - } - - if req.CallbackURL == "" { - sendError(w, http.StatusBadRequest, "callbackUrl is required") - return - } - - id := uuid.New() - - log.Printf("Accepted tree planting: id=%s kind=%q location=%q callbackUrl=%q", - id, req.Kind, req.Location, req.CallbackURL) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusAccepted) - _ = json.NewEncoder(w).Encode(treefarm.TreeWithID{ - Location: req.Location, - Kind: req.Kind, - ID: id, - }) - - go tf.plantAndNotify(id, req) -} - -func (tf *TreeFarm) plantAndNotify(id uuid.UUID, req treefarm.TreePlantingRequest) { - delay := time.Duration(1+rand.IntN(5)) * time.Second - log.Printf("Planting tree %s (kind=%q, location=%q) — will complete in %s", - id, req.Kind, req.Location, delay) - - time.Sleep(delay) - - result := treefarm.TreePlantedJSONRequestBody{ - ID: id, - Kind: req.Kind, - Location: req.Location, - Success: true, - } - - log.Printf("Tree %s planted, invoking callback at %s", id, req.CallbackURL) - - resp, err := tf.initiator.TreePlanted(context.Background(), req.CallbackURL, result) - if err != nil { - log.Printf("Callback to %s failed: %v", req.CallbackURL, err) - return - } - defer func() { _ = resp.Body.Close() }() - - log.Printf("Callback to %s returned status %d", req.CallbackURL, resp.StatusCode) -} - -func main() { - port := flag.String("port", "8080", "Port for HTTP server") - flag.Parse() - - farm := NewTreeFarm() - - mux := http.NewServeMux() - treefarm.HandlerFromMux(farm, mux) - - // Wrap with request logging. - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Printf("%s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) - mux.ServeHTTP(w, r) - }) - - addr := net.JoinHostPort("0.0.0.0", *port) - log.Printf("Tree Farm server listening on %s", addr) - log.Fatal(http.ListenAndServe(addr, handler)) -} diff --git a/experimental/examples/callback/tree-farm.yaml b/experimental/examples/callback/tree-farm.yaml deleted file mode 100644 index 4cad525c08..0000000000 --- a/experimental/examples/callback/tree-farm.yaml +++ /dev/null @@ -1,138 +0,0 @@ -openapi: "3.1.0" -info: - version: 1.0.0 - title: Tree Farm - description: | - A tree planting service that demonstrates OpenAPI callbacks. - The client submits a tree planting request along with a callback URL. - When the tree has been planted, the server sends a POST to the callback URL - to notify the client of the result. - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -paths: - /api/plant_tree: - post: - summary: Request a tree planting - description: | - Submits a request to plant a tree at the specified location. - This is a long-running operation — the server accepts the request - and later notifies the caller via the provided callback URL. - operationId: PlantTree - requestBody: - $ref: '#/components/requestBodies/TreePlanting' - responses: - '202': - description: Tree planting request accepted - content: - application/json: - schema: - $ref: '#/components/schemas/TreeWithId' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - callbacks: - treePlanted: - '{$request.body#/callbackUrl}': - post: - summary: Tree planting result notification - description: | - Sent by the server to the callback URL when the tree planting - operation completes (successfully or not). - operationId: TreePlanted - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TreePlantingResult' - responses: - '200': - description: Callback received successfully - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -components: - schemas: - Tree: - type: object - description: A tree to be planted - required: - - location - - kind - properties: - location: - type: string - description: Where to plant the tree (e.g. "north meadow") - kind: - type: string - description: What kind of tree to plant (e.g. "oak") - - TreePlantingRequest: - description: | - A tree planting request, combining the tree details with a callback URL - for completion notification. - allOf: - - $ref: '#/components/schemas/Tree' - - type: object - required: - - callbackUrl - properties: - callbackUrl: - type: string - format: uri - description: URL to receive the planting result callback - - TreeWithId: - description: A tree with a server-assigned identifier - allOf: - - $ref: '#/components/schemas/Tree' - - type: object - required: - - id - properties: - id: - type: string - format: uuid - description: Unique identifier for this planting request - - TreePlantingResult: - description: The result of a tree planting operation, sent via callback - allOf: - - $ref: '#/components/schemas/TreeWithId' - - type: object - required: - - success - properties: - success: - type: boolean - description: Whether the tree was successfully planted - - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message - - requestBodies: - TreePlanting: - description: Tree planting request - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TreePlantingRequest' diff --git a/experimental/examples/callback/treefarm.gen.go b/experimental/examples/callback/treefarm.gen.go deleted file mode 100644 index a1018c08e9..0000000000 --- a/experimental/examples/callback/treefarm.gen.go +++ /dev/null @@ -1,503 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package treefarm - -import ( - "bytes" - "compress/gzip" - "context" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" - "sync" - - "github.com/google/uuid" -) - -// #/components/schemas/Tree -// A tree to be planted -type Tree struct { - Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") - Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Tree) ApplyDefaults() { -} - -// #/components/schemas/TreePlantingRequest -// A tree planting request, combining the tree details with a callback URL -// for completion notification. -type TreePlantingRequest struct { - Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") - Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") - CallbackURL string `json:"callbackUrl" form:"callbackUrl"` // URL to receive the planting result callback -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TreePlantingRequest) ApplyDefaults() { -} - -// #/components/schemas/TreeWithId -// A tree with a server-assigned identifier -type TreeWithID struct { - Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") - Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") - ID UUID `json:"id" form:"id"` // Unique identifier for this planting request -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TreeWithID) ApplyDefaults() { -} - -// #/components/schemas/TreePlantingResult -// The result of a tree planting operation, sent via callback -type TreePlantingResult struct { - Location string `json:"location" form:"location"` // Where to plant the tree (e.g. "north meadow") - Kind string `json:"kind" form:"kind"` // What kind of tree to plant (e.g. "oak") - ID UUID `json:"id" form:"id"` // Unique identifier for this planting request - Success bool `json:"success" form:"success"` // Whether the tree was successfully planted -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TreePlantingResult) ApplyDefaults() { -} - -// #/components/schemas/Error -type Error struct { - Code int32 `json:"code" form:"code"` // Error code - Message string `json:"message" form:"message"` // Error message -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Error) ApplyDefaults() { -} - -type UUID = uuid.UUID - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/8RXwW7bOBC96ysGaQG3QCO76U23bJEFAhSbIHGQ44IWxxYbilTJUbzG7gL7EfuF+yUL", - "khJFy4rr9NKcopDzZvhm5s1EN6hYIwo4+5R/zBdnmVBrXWQAz2is0KqAj/kiX2QAJEhiAUuDCL8yU2cA", - "HG1pREP+3l8ZAMAlkLvQSKZIqA1YNM+iRKCKEXCstbJkGKGFmwbV5e01lEzKFSufbO4BlhVCKQUqAtuu", - "akEW2AjT4LcWLQGTWm1gK6gCFmHg4e5LQHqsUAFVGKwrZmGFqAIM8g/+yIWHBiwq7vzc3twvgbQ/SgE9", - "HmlQmsR6F45DjHrtvwzaVpLzK0WJymLhTRSrsYDLhpUVwoWnEaA1soCKqLHFfL7dbnPmz3NtNvPO2s6/", - "XH+++u3+6vwiX+QV1TJrGFXWoc5ZI+b+Eb+7hwVHjbYUfgOwbV0zsyvgrudpn7/u2kTy3M99JL2nmXQw", - "7XEYBeoaLMVaIAepS+Zg8giyrIQF4UBcis5Nq5RLnG7Q+Jvw3z//pvyzssSGbEeldxuxmOIgGaEJ7Au0", - "MT1o4Fkw/9kY/Sw48ok6gMHvNS/g1r3FVXF32Pn7RfNdEZ2+NbguYPZmXuq60QoV2flwUaCdO4TbjtFZ", - "hLKNdukbgGYXi4vZ8DmifTld154N5IlVqRWhohQIgDWNFIH6+Ver1f4pgC0rrNn4r9OPC3fDsx4FVdd8", - "lg0hr1kr6cVXtAr/aLAk5IDGaPMz4r5yjvuQo6QMGNSnC3kKPPvzbcd6vtJ892bemz4Y+fdsP4S0x2Ko", - "fa+NM+nkoCvY8NKR4QvdF7vQactql/bIhCzBdk/iRg0+/Ax955iT6OT3nW3LEq1dt1LuQPvuep9nLxi6", - "xlkOFI6uTbZQeigM8gLItHhwPFkhp9XJ8Wo5rdb7Fr7zGZsdPOygoZPGXsymvO5l9nOfLYMlimfkkNKe", - "HdoedNprO+4EXk9l9nvcntSRw4mD6Q4D4jKOLwDaNViAXn3FkqYGVLdXkIYV9iM8GxVYDPM8jqTkT09C", - "9RaNcYVNIs1rb5E+NgRlyew31V5gjxUaHGZkbMZ3mG9yOFPaUAU1Mq63Z+8jiAvm9Z4YeUO/dHRsBK+d", - "M82ezt5nkduhtn17FscH/+X0lvXBacZK+PkdH8eRmJB2aveKeGtterlxypNqYS8zTMqbdZq273XrLLk7", - "UTHT1RCuJ8KenExVQjpBHowcV/8LqeqeXDMqoDXimNw75SbdS0JYX0aTo/c/JDMM5eJIb3TJCOPinFkr", - "Ngo5CI7K703mJ7Au+AlkC/4jHLeCHyVZiW8tJq/3BUluMR2X+FTH2ESG91e2uO27Nhz/axIH5gf3PwX5", - "9TTm8gfpH69jr05CN3JOyER3czodK60lsqOLzGOFVLldpReKLbN7Ey9Kt0fxI+LIBJhS9lJzTD5rtJZt", - "8IiwO4NDqRWKcIPp4OwLSyj6dPGSBvuI92PoInitmgekPvwsXaJi+GlJThfjlGJnR/aug63g2CYwNf1P", - "36d8LLPs/wAAAP//y9dX5mEQAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Request a tree planting - // (POST /api/plant_tree) - PlantTree(w http.ResponseWriter, r *http.Request) -} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -// PlantTree operation middleware -func (siw *ServerInterfaceWrapper) PlantTree(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.PlantTree(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// 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)) - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - -// StdHTTPServerOptions configures the StdHTTP server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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("POST "+options.BaseURL+"/api/plant_tree", wrapper.PlantTree) - return m -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -type TreePlantedJSONRequestBody = TreePlantingResult - -// RequestEditorFn is the function signature for the RequestEditor callback function. -// It may already be defined if client code is also generated; this is a compatible redeclaration. -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// HttpRequestDoer performs HTTP requests. -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// CallbackInitiator sends callback requests to target URLs. -// Unlike Client, it has no stored base URL — the full target URL is provided per-call. -type CallbackInitiator struct { - // 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 -} - -// CallbackInitiatorOption allows setting custom parameters during construction. -type CallbackInitiatorOption func(*CallbackInitiator) error - -// NewCallbackInitiator creates a new CallbackInitiator with reasonable defaults. -func NewCallbackInitiator(opts ...CallbackInitiatorOption) (*CallbackInitiator, error) { - initiator := CallbackInitiator{} - for _, o := range opts { - if err := o(&initiator); err != nil { - return nil, err - } - } - if initiator.Client == nil { - initiator.Client = &http.Client{} - } - return &initiator, nil -} - -// WithCallbackHTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func WithCallbackHTTPClient(doer HttpRequestDoer) CallbackInitiatorOption { - return func(p *CallbackInitiator) error { - p.Client = doer - return nil - } -} - -// WithCallbackRequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func WithCallbackRequestEditorFn(fn RequestEditorFn) CallbackInitiatorOption { - return func(p *CallbackInitiator) error { - p.RequestEditors = append(p.RequestEditors, fn) - return nil - } -} - -func (p *CallbackInitiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range p.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 -} - -// CallbackInitiatorInterface is the interface specification for the callback initiator. -type CallbackInitiatorInterface interface { - // TreePlantedWithBody sends a POST callback request - TreePlantedWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - TreePlanted(ctx context.Context, targetURL string, body TreePlantedJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -// TreePlantedWithBody sends a POST callback request -// Tree planting result notification -func (p *CallbackInitiator) TreePlantedWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewTreePlantedCallbackRequestWithBody(targetURL, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// TreePlanted sends a POST callback request with JSON body -func (p *CallbackInitiator) TreePlanted(ctx context.Context, targetURL string, body TreePlantedJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewTreePlantedCallbackRequest(targetURL, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// NewTreePlantedCallbackRequest creates a POST request for the callback with application/json body -func NewTreePlantedCallbackRequest(targetURL string, body TreePlantedJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewTreePlantedCallbackRequestWithBody(targetURL, "application/json", bodyReader) -} - -// NewTreePlantedCallbackRequestWithBody creates a POST request for the callback with any body -func NewTreePlantedCallbackRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - parsedURL, err := url.Parse(targetURL) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", parsedURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// CallbackHttpError represents an HTTP error response. -// The type parameter E is the type of the parsed error body. -type CallbackHttpError[E any] struct { - StatusCode int - Body E - RawBody []byte -} - -func (e *CallbackHttpError[E]) Error() string { - return fmt.Sprintf("HTTP %d", e.StatusCode) -} - -// SimpleCallbackInitiator wraps CallbackInitiator with typed responses for operations that have -// unambiguous response types. Methods return the success type directly, -// and HTTP errors are returned as *CallbackHttpError[E] where E is the error type. -type SimpleCallbackInitiator struct { - *CallbackInitiator -} - -// NewSimpleCallbackInitiator creates a new SimpleCallbackInitiator which wraps a CallbackInitiator. -func NewSimpleCallbackInitiator(opts ...CallbackInitiatorOption) (*SimpleCallbackInitiator, error) { - initiator, err := NewCallbackInitiator(opts...) - if err != nil { - return nil, err - } - return &SimpleCallbackInitiator{CallbackInitiator: initiator}, nil -} - -// CallbackReceiverInterface represents handlers for receiving callback requests. -type CallbackReceiverInterface interface { - // Tree planting result notification - // HandleTreePlantedCallback handles the POST callback request. - HandleTreePlantedCallback(w http.ResponseWriter, r *http.Request) -} - -// CallbackReceiverMiddlewareFunc is a middleware function for callback receiver handlers. -type CallbackReceiverMiddlewareFunc func(http.Handler) http.Handler - -// TreePlantedCallbackHandler returns an http.Handler for the TreePlanted callback. -// The caller is responsible for registering this handler at the appropriate path. -func TreePlantedCallbackHandler(si CallbackReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...CallbackReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.HandleTreePlantedCallback(w, r) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} diff --git a/experimental/examples/petstore-expanded/chi/Makefile b/experimental/examples/petstore-expanded/chi/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/chi/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/chi/go.mod b/experimental/examples/petstore-expanded/chi/go.mod deleted file mode 100644 index 3c9d10741e..0000000000 --- a/experimental/examples/petstore-expanded/chi/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/chi - -go 1.24.0 - -require ( - github.com/go-chi/chi/v5 v5.2.0 - github.com/google/uuid v1.6.0 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/chi/go.sum b/experimental/examples/petstore-expanded/chi/go.sum deleted file mode 100644 index ad495c8907..0000000000 --- a/experimental/examples/petstore-expanded/chi/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= -github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -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= diff --git a/experimental/examples/petstore-expanded/chi/main.go b/experimental/examples/petstore-expanded/chi/main.go deleted file mode 100644 index 8a4e0e3790..0000000000 --- a/experimental/examples/petstore-expanded/chi/main.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - "net/http" - - "github.com/go-chi/chi/v5" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/chi/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - r := chi.NewRouter() - - // We now register our petStore above as the handler for the interface - server.HandlerFromMux(petStore, r) - - s := &http.Server{ - Handler: r, - Addr: net.JoinHostPort("0.0.0.0", *port), - } - - log.Printf("Server listening on %s", s.Addr) - - // And we serve HTTP until the world ends. - log.Fatal(s.ListenAndServe()) -} diff --git a/experimental/examples/petstore-expanded/chi/server/petstore.go b/experimental/examples/petstore-expanded/chi/server/petstore.go deleted file mode 100644 index 2f52c8e271..0000000000 --- a/experimental/examples/petstore-expanded/chi/server/petstore.go +++ /dev/null @@ -1,135 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "encoding/json" - "fmt" - "net/http" - "sync" - - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(w http.ResponseWriter, code int, message string) { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.Pet - - for _, pet := range p.Pets { - if params.Tags != nil { - // If we have tags, filter pets by tag - for _, t := range *params.Tags { - if pet.Tag != nil && (*pet.Tag == t) { - result = append(result, pet) - } - } - } else { - // Add all pets if we're not filtering - result = append(result, pet) - } - - if params.Limit != nil { - l := int(*params.Limit) - if len(result) >= l { - // We're at the limit - break - } - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { - sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") - return - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _ = json.NewEncoder(w).Encode(pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - delete(p.Pets, id) - - w.WriteHeader(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/chi/server/server.config.yaml b/experimental/examples/petstore-expanded/chi/server/server.config.yaml deleted file mode 100644 index b3b3509411..0000000000 --- a/experimental/examples/petstore-expanded/chi/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: chi - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/chi/server/server.gen.go b/experimental/examples/petstore-expanded/chi/server/server.gen.go deleted file mode 100644 index 167ae93385..0000000000 --- a/experimental/examples/petstore-expanded/chi/server/server.gen.go +++ /dev/null @@ -1,1039 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/go-chi/chi/v5" - "github.com/google/uuid" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) - // Creates a new pet - // (POST /pets) - AddPet(w http.ResponseWriter, r *http.Request) - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(w http.ResponseWriter, r *http.Request, id int64) - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(w http.ResponseWriter, r *http.Request, id int64) -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { - w.WriteHeader(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -// FindPets operation middleware -func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) - return - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPets(w, r, params) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// AddPet operation middleware -func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddPet(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// DeletePet operation middleware -func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, chi.URLParam(r, "id"), &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeletePet(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// FindPetByID operation middleware -func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, chi.URLParam(r, "id"), &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPetByID(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{}) -} - -// ChiServerOptions configures the Chi server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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+"/pets", wrapper.FindPets) - }) - r.Group(func(r chi.Router) { - r.Post(options.BaseURL+"/pets", wrapper.AddPet) - }) - r.Group(func(r chi.Router) { - r.Delete(options.BaseURL+"/pets/{id}", wrapper.DeletePet) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/pets/{id}", wrapper.FindPetByID) - }) - return r -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/client/client.config.yaml b/experimental/examples/petstore-expanded/client/client.config.yaml deleted file mode 100644 index eee5ae5073..0000000000 --- a/experimental/examples/petstore-expanded/client/client.config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -package: client -output: client.gen.go -generation: - client: true - simple-client: true - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/client/client.gen.go b/experimental/examples/petstore-expanded/client/client.gen.go deleted file mode 100644 index d095e9cfda..0000000000 --- a/experimental/examples/petstore-expanded/client/client.gen.go +++ /dev/null @@ -1,1225 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package client - -import ( - "bytes" - "context" - "encoding" - "encoding/json" - "errors" - "fmt" - "github.com/google/uuid" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" - "io" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" -) - -type addPetJSONRequestBody = petstore.NewPet - -// RequestEditorFn is the function signature for the RequestEditor callback function. -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// HttpRequestDoer 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 - -// NewClient creates a new Client with reasonable defaults. -func NewClient(server string, opts ...ClientOption) (*Client, error) { - client := Client{ - Server: server, - } - 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 - } -} - -// 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 - } -} - -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 -} - -// ClientInterface is the interface specification for the client. -type ClientInterface interface { - // FindPets makes a GET request to /pets - FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - // AddPetWithBody makes a POST request to /pets - AddPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // DeletePet makes a DELETE request to /pets/{id} - DeletePet(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) - // FindPetByID makes a GET request to /pets/{id} - FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// FindPets makes a GET request to /pets -// Returns all pets -func (c *Client) FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewFindPetsRequest(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) -} - -// AddPetWithBody makes a POST request to /pets -// Creates a new pet -func (c *Client) AddPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewAddPetRequestWithBody(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) -} - -// AddPet makes a POST request to /pets with JSON body -func (c *Client) AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewAddPetRequest(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) -} - -// DeletePet makes a DELETE request to /pets/{id} -// Deletes a pet by ID -func (c *Client) DeletePet(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewDeletePetRequest(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) -} - -// FindPetByID makes a GET request to /pets/{id} -// Returns a pet by ID -func (c *Client) FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewFindPetByIDRequest(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) -} - -// NewFindPetsRequest creates a GET request for /pets -func NewFindPetsRequest(server string, params *FindPetsParams) (*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 - } - - if params != nil { - queryValues := queryURL.Query() - if params.Tags != nil { - if queryFrag, err := StyleFormExplodeParam("tags", ParamLocationQuery, *params.Tags); 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) - } - } - } - } - if params.Limit != nil { - if queryFrag, err := StyleFormExplodeParam("limit", ParamLocationQuery, *params.Limit); 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) - } - } - } - } - queryURL.RawQuery = queryValues.Encode() - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewAddPetRequest creates a POST request for /pets with application/json body -func NewAddPetRequest(server string, body addPetJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewAddPetRequestWithBody(server, "application/json", bodyReader) -} - -// NewAddPetRequestWithBody creates a POST request for /pets with any body -func NewAddPetRequestWithBody(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("POST", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewDeletePetRequest creates a DELETE request for /pets/{id} -func NewDeletePetRequest(server string, id int64) (*http.Request, error) { - var err error - - var pathParam0 string - pathParam0, err = StyleSimpleParam("id", ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/pets/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("DELETE", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewFindPetByIDRequest creates a GET request for /pets/{id} -func NewFindPetByIDRequest(server string, id int64) (*http.Request, error) { - var err error - - var pathParam0 string - pathParam0, err = StyleSimpleParam("id", ParamLocationPath, id) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/pets/%s", pathParam0) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// ClientHttpError represents an HTTP error response from the server. -// The type parameter E is the type of the parsed error body. -type ClientHttpError[E any] struct { - StatusCode int - Body E - RawBody []byte -} - -func (e *ClientHttpError[E]) Error() string { - return fmt.Sprintf("HTTP %d", e.StatusCode) -} - -// SimpleClient wraps Client with typed responses for operations that have -// unambiguous response types. Methods return the success type directly, -// and HTTP errors are returned as *ClientHttpError[E] where E is the error type. -type SimpleClient struct { - *Client -} - -// NewSimpleClient creates a new SimpleClient which wraps a Client. -func NewSimpleClient(server string, opts ...ClientOption) (*SimpleClient, error) { - client, err := NewClient(server, opts...) - if err != nil { - return nil, err - } - return &SimpleClient{Client: client}, nil -} - -// FindPets makes a GET request to /pets and returns the parsed response. -// Returns all pets -// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. -func (c *SimpleClient) FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) ([]petstore.Pet, error) { - var result []petstore.Pet - resp, err := c.Client.FindPets(ctx, params, reqEditors...) - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // Parse error response - var errBody petstore.Error - _ = json.Unmarshal(rawBody, &errBody) // Best effort parse - return result, &ClientHttpError[petstore.Error]{ - StatusCode: resp.StatusCode, - Body: errBody, - RawBody: rawBody, - } -} - -// AddPet makes a POST request to /pets and returns the parsed response. -// Creates a new pet -// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. -func (c *SimpleClient) AddPet(ctx context.Context, body addPetJSONRequestBody, reqEditors ...RequestEditorFn) (petstore.Pet, error) { - var result petstore.Pet - resp, err := c.Client.AddPet(ctx, body, reqEditors...) - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // Parse error response - var errBody petstore.Error - _ = json.Unmarshal(rawBody, &errBody) // Best effort parse - return result, &ClientHttpError[petstore.Error]{ - StatusCode: resp.StatusCode, - Body: errBody, - RawBody: rawBody, - } -} - -// FindPetByID makes a GET request to /pets/{id} and returns the parsed response. -// Returns a pet by ID -// On success, returns the response body. On HTTP error, returns *ClientHttpError[petstore.Error]. -func (c *SimpleClient) FindPetByID(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (petstore.Pet, error) { - var result petstore.Pet - resp, err := c.Client.FindPetByID(ctx, id, reqEditors...) - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // Parse error response - var errBody petstore.Error - _ = json.Unmarshal(rawBody, &errBody) // Best effort parse - return result, &ClientHttpError[petstore.Error]{ - StatusCode: resp.StatusCode, - Body: errBody, - RawBody: rawBody, - } -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/client/client_test.go b/experimental/examples/petstore-expanded/client/client_test.go deleted file mode 100644 index 76ad5ef8e4..0000000000 --- a/experimental/examples/petstore-expanded/client/client_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package client - -import ( - "context" - "net/http" - "testing" - - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// TestClientTypes verifies all generated types exist and have correct structure. -// If this test compiles, the type generation is correct. -func TestClientTypes(t *testing.T) { - // Core client types - var _ *Client - var _ *SimpleClient - var _ ClientInterface - var _ ClientOption - var _ RequestEditorFn - var _ HttpRequestDoer - - // Param types - var _ *FindPetsParams - - // Request body type alias - var _ addPetJSONRequestBody - - // Error type with generic parameter - var _ *ClientHttpError[petstore.Error] -} - -// TestClientStructure verifies Client struct has expected fields by accessing them. -func TestClientStructure(t *testing.T) { - c := &Client{} - - // Access fields - compiler validates they exist with correct types - var _ = c.Server - var _ = c.Client - var _ = c.RequestEditors -} - -// TestClientImplementsInterface verifies Client implements ClientInterface. -func TestClientImplementsInterface(t *testing.T) { - var _ ClientInterface = (*Client)(nil) -} - -// TestClientInterfaceMethods verifies ClientInterface methods exist with correct signatures. -// The fact that Client implements ClientInterface (tested above) validates all method signatures. -// Here we use method expressions to verify exact signatures without needing an instance. -func TestClientInterfaceMethods(t *testing.T) { - // Method expressions verify signatures at compile time - var _ = (*Client).FindPets - var _ = (*Client).AddPetWithBody - var _ = (*Client).AddPet - var _ = (*Client).DeletePet - var _ = (*Client).FindPetByID -} - -// TestSimpleClientMethods verifies SimpleClient methods return typed responses. -func TestSimpleClientMethods(t *testing.T) { - // Use method expressions to verify signatures without needing an instance - // Compiler validates return types - these use the petstore package types - var _ = (*SimpleClient).FindPets - var _ = (*SimpleClient).AddPet - var _ = (*SimpleClient).FindPetByID -} - -// TestFindPetsParamsStructure verifies param struct fields. -func TestFindPetsParamsStructure(t *testing.T) { - p := &FindPetsParams{} - - // Access fields - compiler validates they exist with correct types - var _ = p.Tags - var _ = p.Limit -} - -// TestRequestBodyTypeAlias verifies the type alias points to correct type. -func TestRequestBodyTypeAlias(t *testing.T) { - // Compiler validates the alias is compatible with petstore.NewPet - var body addPetJSONRequestBody - var newPet petstore.NewPet - - // Bidirectional assignment proves they're the same type - body = newPet - newPet = body - _ = body - _ = newPet -} - -// TestPetstoreTypes verifies that generated types use short names directly. -func TestPetstoreTypes(t *testing.T) { - // Types should be defined directly with short names (no SchemaComponent suffix) - var _ petstore.Pet - var _ petstore.NewPet - var _ petstore.Error -} - -// TestClientHttpErrorImplementsError verifies ClientHttpError implements error interface. -func TestClientHttpErrorImplementsError(t *testing.T) { - var _ error = (*ClientHttpError[petstore.Error])(nil) -} - -// TestClientHttpErrorStructure verifies error type fields. -func TestClientHttpErrorStructure(t *testing.T) { - e := &ClientHttpError[petstore.Error]{} - - // Access fields - compiler validates they exist with correct types - var _ = e.StatusCode - var _ = e.Body - var _ = e.RawBody -} - -// TestRequestBuilders verifies request builder functions exist with correct signatures. -func TestRequestBuilders(t *testing.T) { - var _ = NewFindPetsRequest - var _ = NewAddPetRequestWithBody - var _ = NewAddPetRequest - var _ = NewDeletePetRequest - var _ = NewFindPetByIDRequest -} - -// TestNewClientConstructor verifies the constructor works correctly. -func TestNewClientConstructor(t *testing.T) { - client, err := NewClient("https://api.example.com") - require.NoError(t, err) - require.NotNil(t, client) - - // Verify trailing slash is added - assert.Equal(t, "https://api.example.com/", client.Server) - // Verify default http.Client is created - assert.NotNil(t, client.Client) -} - -// TestClientOptions verifies client options work correctly. -func TestClientOptions(t *testing.T) { - customClient := &http.Client{} - - client, err := NewClient("https://api.example.com", - WithHTTPClient(customClient), - WithRequestEditorFn(func(ctx context.Context, req *http.Request) error { - req.Header.Set("X-Custom", "value") - return nil - }), - ) - require.NoError(t, err) - - assert.Equal(t, customClient, client.Client) - assert.Len(t, client.RequestEditors, 1) -} - -// TestClientHttpErrorMessage verifies the error message format. -func TestClientHttpErrorMessage(t *testing.T) { - err := &ClientHttpError[petstore.Error]{ - StatusCode: 404, - Body: petstore.Error{Code: 404, Message: "Not Found"}, - } - - assert.Contains(t, err.Error(), "404") -} diff --git a/experimental/examples/petstore-expanded/client/validator/main.go b/experimental/examples/petstore-expanded/client/validator/main.go deleted file mode 100644 index d84632f301..0000000000 --- a/experimental/examples/petstore-expanded/client/validator/main.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "context" - "flag" - "log" - "os" - "strings" - - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/client" -) - -func ptr[T any](v T) *T { return &v } - -func main() { - serverURL := flag.String("server", "http://localhost:8080", "Petstore server URL") - flag.Parse() - - log.SetFlags(0) - log.Printf("Petstore Validator") - log.Printf("==================") - log.Printf("Server: %s", *serverURL) - log.Println() - - c, err := client.NewSimpleClient(*serverURL) - if err != nil { - log.Fatalf("Failed to create client: %v", err) - } - ctx := context.Background() - - // Step 1: Add Fido the Dog and Sushi the Cat - log.Println("--- Step 1: Creating pets ---") - - fido, err := c.AddPet(ctx, petstore.NewPet{Name: "Fido", Tag: ptr("Dog")}) - if err != nil { - log.Fatalf("Failed to create Fido: %v", err) - } - log.Printf("Created pet: %s (tag=%s, id=%d)", fido.Name, derefTag(fido.Tag), fido.ID) - - sushi, err := c.AddPet(ctx, petstore.NewPet{Name: "Sushi", Tag: ptr("Cat")}) - if err != nil { - log.Fatalf("Failed to create Sushi: %v", err) - } - log.Printf("Created pet: %s (tag=%s, id=%d)", sushi.Name, derefTag(sushi.Tag), sushi.ID) - log.Println() - - // Step 2: List all pets - log.Println("--- Step 2: Listing all pets ---") - pets, err := c.FindPets(ctx, nil) - if err != nil { - log.Fatalf("Failed to list pets: %v", err) - } - printPets(pets) - log.Println() - - // Step 3: Delete Fido - log.Printf("--- Step 3: Deleting Fido (id=%d) ---", fido.ID) - resp, err := c.DeletePet(ctx, fido.ID) - if err != nil { - log.Fatalf("Failed to delete Fido: %v", err) - } - _ = resp.Body.Close() - if resp.StatusCode == 204 { - log.Printf("Deleted Fido successfully (HTTP %d)", resp.StatusCode) - } else { - log.Fatalf("Unexpected status deleting Fido: HTTP %d", resp.StatusCode) - } - log.Println() - - // Step 4: Add Slimy the Lizard - log.Println("--- Step 4: Creating Slimy the Lizard ---") - slimy, err := c.AddPet(ctx, petstore.NewPet{Name: "Slimy", Tag: ptr("Lizard")}) - if err != nil { - log.Fatalf("Failed to create Slimy: %v", err) - } - log.Printf("Created pet: %s (tag=%s, id=%d)", slimy.Name, derefTag(slimy.Tag), slimy.ID) - log.Println() - - // Step 5: List all pets again - log.Println("--- Step 5: Listing all pets (after changes) ---") - pets, err = c.FindPets(ctx, nil) - if err != nil { - log.Fatalf("Failed to list pets: %v", err) - } - printPets(pets) - log.Println() - - // Validate final state - log.Println("--- Validation ---") - ok := true - if len(pets) != 2 { - log.Printf("FAIL: expected 2 pets, got %d", len(pets)) - ok = false - } - names := map[string]bool{} - for _, p := range pets { - names[p.Name] = true - } - if !names["Sushi"] { - log.Printf("FAIL: Sushi not found in pet list") - ok = false - } - if !names["Slimy"] { - log.Printf("FAIL: Slimy not found in pet list") - ok = false - } - if names["Fido"] { - log.Printf("FAIL: Fido should have been deleted but is still present") - ok = false - } - - if ok { - log.Println("PASS: All validations passed!") - } else { - log.Println("FAIL: Some validations failed") - os.Exit(1) - } -} - -func derefTag(tag *string) string { - if tag == nil { - return "" - } - return *tag -} - -func printPets(pets []petstore.Pet) { - if len(pets) == 0 { - log.Println(" (no pets)") - return - } - maxName := 0 - for _, p := range pets { - if len(p.Name) > maxName { - maxName = len(p.Name) - } - } - for _, p := range pets { - padding := strings.Repeat(" ", maxName-len(p.Name)) - log.Printf(" - %s%s tag=%-8s id=%d", p.Name, padding, derefTag(p.Tag), p.ID) - } -} diff --git a/experimental/examples/petstore-expanded/doc.go b/experimental/examples/petstore-expanded/doc.go deleted file mode 100644 index d3e6eede3d..0000000000 --- a/experimental/examples/petstore-expanded/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package petstore provides generated types for the Petstore API. -package petstore diff --git a/experimental/examples/petstore-expanded/echo-v4/Makefile b/experimental/examples/petstore-expanded/echo-v4/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/echo-v4/go.mod b/experimental/examples/petstore-expanded/echo-v4/go.mod deleted file mode 100644 index 241f767a53..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo-v4 - -go 1.24.0 - -require ( - github.com/google/uuid v1.6.0 - github.com/labstack/echo/v4 v4.13.3 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -require ( - github.com/labstack/gommon v0.4.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.33.0 // indirect -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/echo-v4/go.sum b/experimental/examples/petstore-expanded/echo-v4/go.sum deleted file mode 100644 index d6b2e1f6c1..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/go.sum +++ /dev/null @@ -1,33 +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/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/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= -github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -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/experimental/examples/petstore-expanded/echo-v4/main.go b/experimental/examples/petstore-expanded/echo-v4/main.go deleted file mode 100644 index 5f89fc8cd3..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/main.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - - "github.com/labstack/echo/v4" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo-v4/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - e := echo.New() - - // We now register our petStore above as the handler for the interface - server.RegisterHandlers(e, petStore) - - log.Printf("Server listening on %s", net.JoinHostPort("0.0.0.0", *port)) - - // And we serve HTTP until the world ends. - log.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port))) -} diff --git a/experimental/examples/petstore-expanded/echo-v4/server/petstore.go b/experimental/examples/petstore-expanded/echo-v4/server/petstore.go deleted file mode 100644 index 9ee8d05a1b..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/server/petstore.go +++ /dev/null @@ -1,123 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "net/http" - "sync" - - "github.com/labstack/echo/v4" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(ctx echo.Context, code int, message string) error { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - return ctx.JSON(code, petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(ctx echo.Context, params FindPetsParams) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.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) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(ctx echo.Context) error { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := ctx.Bind(&newPet); err != nil { - return sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - return ctx.JSON(http.StatusCreated, pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(ctx echo.Context, id int64) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - return sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") - } - - return ctx.JSON(http.StatusOK, pet) -} - -// DeletePet deletes a pet by ID. -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, "Could not find pet with ID") - } - delete(p.Pets, id) - - return ctx.NoContent(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml b/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml deleted file mode 100644 index c4f40a9a65..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: echo/v4 - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go b/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go deleted file mode 100644 index af329680a5..0000000000 --- a/experimental/examples/petstore-expanded/echo-v4/server/server.gen.go +++ /dev/null @@ -1,976 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/google/uuid" - "github.com/labstack/echo/v4" -) - -// 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 -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(ctx echo.Context, params FindPetsParams) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(ctx echo.Context) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(ctx echo.Context, id int64) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(ctx echo.Context, id int64) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// 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 = BindFormExplodeParam("tags", false, ctx.QueryParams(), ¶ms.Tags) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, ctx.QueryParams(), ¶ms.Limit) - 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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.FindPetByID(ctx, id) - return err -} - -// EchoRouter is an interface for echo.Echo and echo.Group. -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, "") -} - -// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { - - 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) -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/echo/Makefile b/experimental/examples/petstore-expanded/echo/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/echo/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/echo/go.mod b/experimental/examples/petstore-expanded/echo/go.mod deleted file mode 100644 index 3576808d2d..0000000000 --- a/experimental/examples/petstore-expanded/echo/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo - -go 1.25.0 - -require ( - github.com/google/uuid v1.6.0 - github.com/labstack/echo/v5 v5.0.0 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/echo/go.sum b/experimental/examples/petstore-expanded/echo/go.sum deleted file mode 100644 index 9dd4179c6c..0000000000 --- a/experimental/examples/petstore-expanded/echo/go.sum +++ /dev/null @@ -1,16 +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/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/labstack/echo/v5 v5.0.0 h1:JHKGrI0cbNsNMyKvranuY0C94O4hSM7yc/HtwcV3Na4= -github.com/labstack/echo/v5 v5.0.0/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= -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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -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/experimental/examples/petstore-expanded/echo/main.go b/experimental/examples/petstore-expanded/echo/main.go deleted file mode 100644 index 6f0483ac28..0000000000 --- a/experimental/examples/petstore-expanded/echo/main.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - - "github.com/labstack/echo/v5" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/echo/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - e := echo.New() - - // We now register our petStore above as the handler for the interface - server.RegisterHandlers(e, petStore) - - log.Printf("Server listening on %s", net.JoinHostPort("0.0.0.0", *port)) - - // And we serve HTTP until the world ends. - log.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port))) -} diff --git a/experimental/examples/petstore-expanded/echo/server/petstore.go b/experimental/examples/petstore-expanded/echo/server/petstore.go deleted file mode 100644 index 276030da81..0000000000 --- a/experimental/examples/petstore-expanded/echo/server/petstore.go +++ /dev/null @@ -1,123 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "net/http" - "sync" - - "github.com/labstack/echo/v5" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(ctx *echo.Context, code int, message string) error { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - return ctx.JSON(code, petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(ctx *echo.Context, params FindPetsParams) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.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) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(ctx *echo.Context) error { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := ctx.Bind(&newPet); err != nil { - return sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - return ctx.JSON(http.StatusCreated, pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(ctx *echo.Context, id int64) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - return sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") - } - - return ctx.JSON(http.StatusOK, pet) -} - -// DeletePet deletes a pet by ID. -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, "Could not find pet with ID") - } - delete(p.Pets, id) - - return ctx.NoContent(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/echo/server/server.config.yaml b/experimental/examples/petstore-expanded/echo/server/server.config.yaml deleted file mode 100644 index 16a0b6b82d..0000000000 --- a/experimental/examples/petstore-expanded/echo/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: echo - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/echo/server/server.gen.go b/experimental/examples/petstore-expanded/echo/server/server.gen.go deleted file mode 100644 index da099a985f..0000000000 --- a/experimental/examples/petstore-expanded/echo/server/server.gen.go +++ /dev/null @@ -1,977 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/google/uuid" - "github.com/labstack/echo/v5" -) - -// 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 -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(ctx *echo.Context, params FindPetsParams) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(ctx *echo.Context) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(ctx *echo.Context, id int64) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(ctx *echo.Context, id int64) error { - return ctx.NoContent(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// 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 = BindFormExplodeParam("tags", false, ctx.QueryParams(), ¶ms.Tags) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, ctx.QueryParams(), ¶ms.Limit) - 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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.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 = BindSimpleParam("id", ParamLocationPath, ctx.Param("id"), &id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.FindPetByID(ctx, id) - return err -} - -// EchoRouter is an interface for echo.Echo and echo.Group. -type EchoRouter interface { - Add(method string, path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo - 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 -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router EchoRouter, si ServerInterface) { - RegisterHandlersWithBaseURL(router, si, "") -} - -// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { - - 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) -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/fiber/Makefile b/experimental/examples/petstore-expanded/fiber/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/fiber/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/fiber/go.mod b/experimental/examples/petstore-expanded/fiber/go.mod deleted file mode 100644 index aa60e0d81c..0000000000 --- a/experimental/examples/petstore-expanded/fiber/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/fiber - -go 1.24.0 - -require ( - github.com/gofiber/fiber/v3 v3.0.0-beta.4 - github.com/google/uuid v1.6.0 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -require ( - github.com/andybalholm/brotli v1.1.1 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/gofiber/schema v1.2.0 // indirect - github.com/gofiber/utils/v2 v2.0.0-beta.7 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect - github.com/tinylib/msgp v1.2.5 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.58.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/x448/float16 v0.8.4 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.33.0 // indirect -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/fiber/go.sum b/experimental/examples/petstore-expanded/fiber/go.sum deleted file mode 100644 index 00a56bd56e..0000000000 --- a/experimental/examples/petstore-expanded/fiber/go.sum +++ /dev/null @@ -1,51 +0,0 @@ -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -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/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gofiber/fiber/v3 v3.0.0-beta.4 h1:KzDSavvhG7m81NIsmnu5l3ZDbVS4feCidl4xlIfu6V0= -github.com/gofiber/fiber/v3 v3.0.0-beta.4/go.mod h1:/WFUoHRkZEsGHyy2+fYcdqi109IVOFbVwxv1n1RU+kk= -github.com/gofiber/schema v1.2.0 h1:j+ZRrNnUa/0ZuWrn/6kAtAufEr4jCJ+JuTURAMxNSZg= -github.com/gofiber/schema v1.2.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c= -github.com/gofiber/utils/v2 v2.0.0-beta.7 h1:NnHFrRHvhrufPABdWajcKZejz9HnCWmT/asoxRsiEbQ= -github.com/gofiber/utils/v2 v2.0.0-beta.7/go.mod h1:J/M03s+HMdZdvhAeyh76xT72IfVqBzuz/OJkrMa7cwU= -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/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -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/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= -github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= -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.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE= -github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw= -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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= -github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -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/experimental/examples/petstore-expanded/fiber/main.go b/experimental/examples/petstore-expanded/fiber/main.go deleted file mode 100644 index a429cc08f3..0000000000 --- a/experimental/examples/petstore-expanded/fiber/main.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - - "github.com/gofiber/fiber/v3" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/fiber/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - app := fiber.New() - - // We now register our petStore above as the handler for the interface - server.RegisterHandlers(app, petStore) - - addr := net.JoinHostPort("0.0.0.0", *port) - log.Printf("Server listening on %s", addr) - - // And we serve HTTP until the world ends. - log.Fatal(app.Listen(addr)) -} diff --git a/experimental/examples/petstore-expanded/fiber/server/petstore.go b/experimental/examples/petstore-expanded/fiber/server/petstore.go deleted file mode 100644 index 0692078618..0000000000 --- a/experimental/examples/petstore-expanded/fiber/server/petstore.go +++ /dev/null @@ -1,122 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "sync" - - "github.com/gofiber/fiber/v3" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(c fiber.Ctx, code int, message string) error { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - return c.Status(code).JSON(petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(c fiber.Ctx, params FindPetsParams) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.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 c.Status(fiber.StatusOK).JSON(result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(c fiber.Ctx) error { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := c.Bind().JSON(&newPet); err != nil { - return sendPetStoreError(c, fiber.StatusBadRequest, "Invalid format for NewPet") - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - return c.Status(fiber.StatusCreated).JSON(pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(c fiber.Ctx, id int64) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - return sendPetStoreError(c, fiber.StatusNotFound, "Could not find pet with ID") - } - - return c.Status(fiber.StatusOK).JSON(pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(c fiber.Ctx, id int64) error { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - return sendPetStoreError(c, fiber.StatusNotFound, "Could not find pet with ID") - } - delete(p.Pets, id) - - return c.SendStatus(fiber.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/fiber/server/server.config.yaml b/experimental/examples/petstore-expanded/fiber/server/server.config.yaml deleted file mode 100644 index 1038e55a98..0000000000 --- a/experimental/examples/petstore-expanded/fiber/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: fiber - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/fiber/server/server.gen.go b/experimental/examples/petstore-expanded/fiber/server/server.gen.go deleted file mode 100644 index a38d4cfb87..0000000000 --- a/experimental/examples/petstore-expanded/fiber/server/server.gen.go +++ /dev/null @@ -1,969 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/gofiber/fiber/v3" - "github.com/google/uuid" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(c fiber.Ctx, params FindPetsParams) error - // Creates a new pet - // (POST /pets) - AddPet(c fiber.Ctx) error - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(c fiber.Ctx, id int64) error - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(c fiber.Ctx, id int64) error -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(c fiber.Ctx, params FindPetsParams) error { - return c.SendStatus(fiber.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(c fiber.Ctx) error { - return c.SendStatus(fiber.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(c fiber.Ctx, id int64) error { - return c.SendStatus(fiber.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(c fiber.Ctx, id int64) error { - return c.SendStatus(fiber.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// FindPets operation middleware -func (siw *ServerInterfaceWrapper) FindPets(c fiber.Ctx) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - var query url.Values - query, err = url.ParseQuery(string(c.Request().URI().QueryString())) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for query string: %s", err)) - } - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, query, ¶ms.Tags) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err)) - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, query, ¶ms.Limit) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) - } - - return siw.Handler.FindPets(c, params) -} - -// AddPet operation middleware -func (siw *ServerInterfaceWrapper) AddPet(c fiber.Ctx) error { - - return siw.Handler.AddPet(c) -} - -// DeletePet operation middleware -func (siw *ServerInterfaceWrapper) DeletePet(c fiber.Ctx) error { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, c.Params("id"), &id) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - return siw.Handler.DeletePet(c, id) -} - -// FindPetByID operation middleware -func (siw *ServerInterfaceWrapper) FindPetByID(c fiber.Ctx) error { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, c.Params("id"), &id) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - return siw.Handler.FindPetByID(c, id) -} - -// FiberServerOptions provides options for the Fiber server. -type FiberServerOptions struct { - BaseURL string - Middlewares []fiber.Handler -} - -// 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, - } - - for _, m := range options.Middlewares { - router.Use(m) - } - - router.Get(options.BaseURL+"/pets", wrapper.FindPets) - router.Post(options.BaseURL+"/pets", wrapper.AddPet) - router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet) - router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID) -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/generate.go b/experimental/examples/petstore-expanded/generate.go deleted file mode 100644 index b8a15f94ef..0000000000 --- a/experimental/examples/petstore-expanded/generate.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config models.config.yaml petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config stdhttp/server/server.config.yaml -output stdhttp/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config chi/server/server.config.yaml -output chi/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config echo-v4/server/server.config.yaml -output echo-v4/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config echo/server/server.config.yaml -output echo/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config gin/server/server.config.yaml -output gin/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config gorilla/server/server.config.yaml -output gorilla/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config fiber/server/server.config.yaml -output fiber/server/server.gen.go petstore-expanded.yaml -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config iris/server/server.config.yaml -output iris/server/server.gen.go petstore-expanded.yaml - -package petstore diff --git a/experimental/examples/petstore-expanded/gin/Makefile b/experimental/examples/petstore-expanded/gin/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/gin/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/gin/go.mod b/experimental/examples/petstore-expanded/gin/go.mod deleted file mode 100644 index eed1c070da..0000000000 --- a/experimental/examples/petstore-expanded/gin/go.mod +++ /dev/null @@ -1,40 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gin - -go 1.24.0 - -require ( - github.com/gin-gonic/gin v1.10.0 - github.com/google/uuid v1.6.0 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -require ( - 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/gabriel-vasile/mimetype v1.4.3 // indirect - github.com/gin-contrib/sse v0.1.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/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.33.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/gin/go.sum b/experimental/examples/petstore-expanded/gin/go.sum deleted file mode 100644 index fa550cb75e..0000000000 --- a/experimental/examples/petstore-expanded/gin/go.sum +++ /dev/null @@ -1,92 +0,0 @@ -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/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/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/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-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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -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/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/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/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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -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/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/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= -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= -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/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -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/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/experimental/examples/petstore-expanded/gin/main.go b/experimental/examples/petstore-expanded/gin/main.go deleted file mode 100644 index 91148c8846..0000000000 --- a/experimental/examples/petstore-expanded/gin/main.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gin/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - r := gin.Default() - - // We now register our petStore above as the handler for the interface - server.RegisterHandlers(r, petStore) - - s := &http.Server{ - Handler: r, - Addr: net.JoinHostPort("0.0.0.0", *port), - } - - log.Printf("Server listening on %s", s.Addr) - - // And we serve HTTP until the world ends. - log.Fatal(s.ListenAndServe()) -} diff --git a/experimental/examples/petstore-expanded/gin/server/petstore.go b/experimental/examples/petstore-expanded/gin/server/petstore.go deleted file mode 100644 index 45f4801f25..0000000000 --- a/experimental/examples/petstore-expanded/gin/server/petstore.go +++ /dev/null @@ -1,126 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "net/http" - "sync" - - "github.com/gin-gonic/gin" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(c *gin.Context, code int, message string) { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - c.JSON(code, petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(c *gin.Context, params FindPetsParams) { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.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 - } - } - } - - c.JSON(http.StatusOK, result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(c *gin.Context) { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := c.ShouldBindJSON(&newPet); err != nil { - sendPetStoreError(c, http.StatusBadRequest, "Invalid format for NewPet") - return - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - c.JSON(http.StatusCreated, pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(c *gin.Context, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - sendPetStoreError(c, http.StatusNotFound, "Could not find pet with ID") - return - } - - c.JSON(http.StatusOK, pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(c *gin.Context, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - sendPetStoreError(c, http.StatusNotFound, "Could not find pet with ID") - return - } - delete(p.Pets, id) - - c.Status(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/gin/server/server.config.yaml b/experimental/examples/petstore-expanded/gin/server/server.config.yaml deleted file mode 100644 index 9b26a5e3b9..0000000000 --- a/experimental/examples/petstore-expanded/gin/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: gin - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/gin/server/server.gen.go b/experimental/examples/petstore-expanded/gin/server/server.gen.go deleted file mode 100644 index 87d877c5c8..0000000000 --- a/experimental/examples/petstore-expanded/gin/server/server.gen.go +++ /dev/null @@ -1,1007 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(c *gin.Context, params FindPetsParams) - // Creates a new pet - // (POST /pets) - AddPet(c *gin.Context) - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(c *gin.Context, id int64) - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(c *gin.Context, id int64) -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(c *gin.Context, params FindPetsParams) { - c.Status(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(c *gin.Context) { - c.Status(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(c *gin.Context, id int64) { - c.Status(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(c *gin.Context, id int64) { - c.Status(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(c *gin.Context) - -// FindPets operation middleware -func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, c.Request.URL.Query(), ¶ms.Tags) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter tags: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, c.Request.URL.Query(), ¶ms.Limit) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter limit: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.FindPets(c, params) -} - -// AddPet operation middleware -func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.AddPet(c) -} - -// DeletePet operation middleware -func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, c.Param("id"), &id) - 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.DeletePet(c, id) -} - -// FindPetByID operation middleware -func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, c.Param("id"), &id) - 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.FindPetByID(c, id) -} - -// 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+"/pets", wrapper.FindPets) - router.POST(options.BaseURL+"/pets", wrapper.AddPet) - router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet) - router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID) -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/gorilla/Makefile b/experimental/examples/petstore-expanded/gorilla/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/gorilla/go.mod b/experimental/examples/petstore-expanded/gorilla/go.mod deleted file mode 100644 index fa094711da..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gorilla - -go 1.24.0 - -require ( - github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.1 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.0 -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/gorilla/go.sum b/experimental/examples/petstore-expanded/gorilla/go.sum deleted file mode 100644 index c9af5271c5..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= diff --git a/experimental/examples/petstore-expanded/gorilla/main.go b/experimental/examples/petstore-expanded/gorilla/main.go deleted file mode 100644 index 1bde88bcca..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/main.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - "net/http" - - "github.com/gorilla/mux" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/gorilla/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - r := mux.NewRouter() - - // We now register our petStore above as the handler for the interface - server.HandlerFromMux(petStore, r) - - s := &http.Server{ - Handler: r, - Addr: net.JoinHostPort("0.0.0.0", *port), - } - - log.Printf("Server listening on %s", s.Addr) - - // And we serve HTTP until the world ends. - log.Fatal(s.ListenAndServe()) -} diff --git a/experimental/examples/petstore-expanded/gorilla/server/petstore.go b/experimental/examples/petstore-expanded/gorilla/server/petstore.go deleted file mode 100644 index 2f52c8e271..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/server/petstore.go +++ /dev/null @@ -1,135 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "encoding/json" - "fmt" - "net/http" - "sync" - - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(w http.ResponseWriter, code int, message string) { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.Pet - - for _, pet := range p.Pets { - if params.Tags != nil { - // If we have tags, filter pets by tag - for _, t := range *params.Tags { - if pet.Tag != nil && (*pet.Tag == t) { - result = append(result, pet) - } - } - } else { - // Add all pets if we're not filtering - result = append(result, pet) - } - - if params.Limit != nil { - l := int(*params.Limit) - if len(result) >= l { - // We're at the limit - break - } - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { - sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") - return - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _ = json.NewEncoder(w).Encode(pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - delete(p.Pets, id) - - w.WriteHeader(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml b/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml deleted file mode 100644 index 5de1d21f15..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: gorilla - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/gorilla/server/server.gen.go b/experimental/examples/petstore-expanded/gorilla/server/server.gen.go deleted file mode 100644 index 957f88149e..0000000000 --- a/experimental/examples/petstore-expanded/gorilla/server/server.gen.go +++ /dev/null @@ -1,1035 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/google/uuid" - "github.com/gorilla/mux" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) - // Creates a new pet - // (POST /pets) - AddPet(w http.ResponseWriter, r *http.Request) - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(w http.ResponseWriter, r *http.Request, id int64) - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(w http.ResponseWriter, r *http.Request, id int64) -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { - w.WriteHeader(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { - w.WriteHeader(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -// FindPets operation middleware -func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) - return - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPets(w, r, params) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// AddPet operation middleware -func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddPet(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// DeletePet operation middleware -func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { - var err error - - pathParams := mux.Vars(r) - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, pathParams["id"], &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeletePet(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// FindPetByID operation middleware -func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { - var err error - - pathParams := mux.Vars(r) - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, pathParams["id"], &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPetByID(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, GorillaServerOptions{}) -} - -// GorillaServerOptions configures the Gorilla server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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+"/pets", wrapper.FindPets).Methods("GET") - r.HandleFunc(options.BaseURL+"/pets", wrapper.AddPet).Methods("POST") - r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.DeletePet).Methods("DELETE") - r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.FindPetByID).Methods("GET") - return r -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/iris/Makefile b/experimental/examples/petstore-expanded/iris/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/iris/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/iris/go.mod b/experimental/examples/petstore-expanded/iris/go.mod deleted file mode 100644 index b13819f2a5..0000000000 --- a/experimental/examples/petstore-expanded/iris/go.mod +++ /dev/null @@ -1,55 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/iris - -go 1.24.0 - -require ( - github.com/google/uuid v1.6.0 - github.com/kataras/iris/v12 v12.2.11 - github.com/oapi-codegen/oapi-codegen/experimental v0.0.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/Joker/jade v1.1.3 // indirect - github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/aymerick/douceur v0.2.0 // indirect - github.com/fatih/structs v1.1.0 // indirect - github.com/flosch/pongo2/v4 v4.0.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect - github.com/gorilla/css v1.0.0 // indirect - github.com/iris-contrib/schema v0.0.6 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/kataras/blocks v0.0.8 // 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.7 // indirect - github.com/mailgun/raymond/v2 v2.0.48 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/microcosm-cc/bluemonday v1.0.26 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/schollz/closestmatch v2.1.0+incompatible // indirect - github.com/sirupsen/logrus v1.8.1 // indirect - github.com/tdewolff/minify/v2 v2.20.19 // indirect - github.com/tdewolff/parse/v2 v2.7.12 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/yosssi/ace v0.0.5 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/iris/go.sum b/experimental/examples/petstore-expanded/iris/go.sum deleted file mode 100644 index a06439c9fc..0000000000 --- a/experimental/examples/petstore-expanded/iris/go.sum +++ /dev/null @@ -1,178 +0,0 @@ -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= -github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= -github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= -github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= -github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= -github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -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-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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/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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= -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= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= -github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= -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.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= -github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= -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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= -github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= -github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= -github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= -github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= -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/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/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/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.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -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/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.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/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= -moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs= -moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= diff --git a/experimental/examples/petstore-expanded/iris/main.go b/experimental/examples/petstore-expanded/iris/main.go deleted file mode 100644 index 48d035a84d..0000000000 --- a/experimental/examples/petstore-expanded/iris/main.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - - "github.com/kataras/iris/v12" - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/iris/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - app := iris.New() - - // We now register our petStore above as the handler for the interface - server.RegisterHandlers(app, petStore) - - addr := net.JoinHostPort("0.0.0.0", *port) - log.Printf("Server listening on %s", addr) - - // And we serve HTTP until the world ends. - log.Fatal(app.Listen(addr)) -} diff --git a/experimental/examples/petstore-expanded/iris/server/petstore.go b/experimental/examples/petstore-expanded/iris/server/petstore.go deleted file mode 100644 index cab647706c..0000000000 --- a/experimental/examples/petstore-expanded/iris/server/petstore.go +++ /dev/null @@ -1,130 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "net/http" - "sync" - - "github.com/kataras/iris/v12" - petstore "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded" -) - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]petstore.Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]petstore.Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(ctx iris.Context, code int, message string) { - petErr := petstore.Error{ - Code: int32(code), - Message: message, - } - ctx.StatusCode(code) - _ = ctx.JSON(petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(ctx iris.Context, params FindPetsParams) { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []petstore.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 - } - } - } - - ctx.StatusCode(http.StatusOK) - _ = ctx.JSON(result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(ctx iris.Context) { - // We expect a NewPet object in the request body. - var newPet petstore.NewPet - if err := ctx.ReadJSON(&newPet); err != nil { - sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet") - return - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet petstore.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 Pet - ctx.StatusCode(http.StatusCreated) - _ = ctx.JSON(pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(ctx iris.Context, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") - return - } - - ctx.StatusCode(http.StatusOK) - _ = ctx.JSON(pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(ctx iris.Context, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - sendPetStoreError(ctx, http.StatusNotFound, "Could not find pet with ID") - return - } - delete(p.Pets, id) - - ctx.StatusCode(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/iris/server/server.config.yaml b/experimental/examples/petstore-expanded/iris/server/server.config.yaml deleted file mode 100644 index 443b44a84b..0000000000 --- a/experimental/examples/petstore-expanded/iris/server/server.config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: server -generation: - server: iris - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/iris/server/server.gen.go b/experimental/examples/petstore-expanded/iris/server/server.gen.go deleted file mode 100644 index 1c59478225..0000000000 --- a/experimental/examples/petstore-expanded/iris/server/server.gen.go +++ /dev/null @@ -1,973 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/google/uuid" - "github.com/kataras/iris/v12" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(ctx iris.Context, params FindPetsParams) - // Creates a new pet - // (POST /pets) - AddPet(ctx iris.Context) - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(ctx iris.Context, id int64) - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(ctx iris.Context, id int64) -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -// Returns all pets -// (GET /pets) -func (_ Unimplemented) FindPets(ctx iris.Context, params FindPetsParams) { - ctx.StatusCode(http.StatusNotImplemented) -} - -// Creates a new pet -// (POST /pets) -func (_ Unimplemented) AddPet(ctx iris.Context) { - ctx.StatusCode(http.StatusNotImplemented) -} - -// Deletes a pet by ID -// (DELETE /pets/{id}) -func (_ Unimplemented) DeletePet(ctx iris.Context, id int64) { - ctx.StatusCode(http.StatusNotImplemented) -} - -// Returns a pet by ID -// (GET /pets/{id}) -func (_ Unimplemented) FindPetByID(ctx iris.Context, id int64) { - ctx.StatusCode(http.StatusNotImplemented) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts iris contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// FindPets converts iris context to params. -func (w *ServerInterfaceWrapper) FindPets(ctx iris.Context) { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, ctx.Request().URL.Query(), ¶ms.Tags) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter tags: %s", err)) - return - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, ctx.Request().URL.Query(), ¶ms.Limit) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter limit: %s", err)) - return - } - - // Invoke the callback with all the unmarshaled arguments - w.Handler.FindPets(ctx, params) -} - -// AddPet converts iris context to params. -func (w *ServerInterfaceWrapper) AddPet(ctx iris.Context) { - - // Invoke the callback with all the unmarshaled arguments - w.Handler.AddPet(ctx) -} - -// DeletePet converts iris context to params. -func (w *ServerInterfaceWrapper) DeletePet(ctx iris.Context) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, ctx.Params().Get("id"), &id) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter id: %s", err)) - return - } - - // Invoke the callback with all the unmarshaled arguments - w.Handler.DeletePet(ctx, id) -} - -// FindPetByID converts iris context to params. -func (w *ServerInterfaceWrapper) FindPetByID(ctx iris.Context) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, ctx.Params().Get("id"), &id) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter id: %s", err)) - return - } - - // Invoke the callback with all the unmarshaled arguments - w.Handler.FindPetByID(ctx, id) -} - -// IrisServerOptions is the option for iris server. -type IrisServerOptions struct { - BaseURL string - Middlewares []iris.Handler -} - -// 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+"/pets", wrapper.FindPets) - router.Post(options.BaseURL+"/pets", wrapper.AddPet) - router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet) - router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID) - router.Build() -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/petstore-expanded/models.config.yaml b/experimental/examples/petstore-expanded/models.config.yaml deleted file mode 100644 index 47d99a649f..0000000000 --- a/experimental/examples/petstore-expanded/models.config.yaml +++ /dev/null @@ -1,2 +0,0 @@ -package: petstore -output: petstore.gen.go diff --git a/experimental/examples/petstore-expanded/petstore-expanded.yaml b/experimental/examples/petstore-expanded/petstore-expanded.yaml deleted file mode 100644 index f9f84f2854..0000000000 --- a/experimental/examples/petstore-expanded/petstore-expanded.yaml +++ /dev/null @@ -1,164 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Swagger Petstore - description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification - termsOfService: https://swagger.io/terms/ - contact: - name: Swagger API Team - email: apiteam@swagger.io - url: https://swagger.io - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -servers: - - url: https://petstore.swagger.io/api -paths: - /pets: - get: - summary: Returns all pets - description: | - Returns all pets from the system that the user has access to - Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. - - Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. - operationId: findPets - parameters: - - name: tags - in: query - description: tags to filter by - required: false - style: form - schema: - type: array - items: - type: string - - name: limit - in: query - description: maximum number of results to return - required: false - schema: - type: integer - format: int32 - responses: - '200': - description: pet response - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: Creates a new pet - description: Creates a new pet in the store. Duplicates are allowed - operationId: addPet - requestBody: - description: Pet to add to the store - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NewPet' - responses: - '200': - description: pet response - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /pets/{id}: - get: - summary: Returns a pet by ID - description: Returns a pet based on a single ID - operationId: findPetByID - parameters: - - name: id - in: path - description: ID of pet to fetch - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: pet response - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: Deletes a pet by ID - description: deletes a single pet based on the ID supplied - operationId: deletePet - parameters: - - name: id - in: path - description: ID of pet to delete - required: true - schema: - type: integer - format: int64 - responses: - '204': - description: pet deleted - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -components: - schemas: - Pet: - allOf: - - $ref: '#/components/schemas/NewPet' - - required: - - id - properties: - id: - type: integer - format: int64 - description: Unique id of the pet - - NewPet: - required: - - name - properties: - name: - type: string - description: Name of the pet - tag: - type: string - description: Type of the pet - - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message diff --git a/experimental/examples/petstore-expanded/petstore.gen.go b/experimental/examples/petstore-expanded/petstore.gen.go deleted file mode 100644 index 4149df2b00..0000000000 --- a/experimental/examples/petstore-expanded/petstore.gen.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package petstore - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Pet -type Pet struct { - Name string `json:"name" form:"name"` // Name of the pet - Tag *string `json:"tag,omitempty" form:"tag,omitempty"` // Type of the pet - ID int64 `json:"id" form:"id"` // Unique id of the pet -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Pet) ApplyDefaults() { -} - -// #/components/schemas/NewPet -type NewPet struct { - Name string `json:"name" form:"name"` // Name of the pet - Tag *string `json:"tag,omitempty" form:"tag,omitempty"` // Type of the pet -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NewPet) ApplyDefaults() { -} - -// #/components/schemas/Error -type Error struct { - Code int32 `json:"code" form:"code"` // Error code - Message string `json:"message" form:"message"` // Error message -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Error) ApplyDefaults() { -} - -// #/paths//pets/get/responses/200/content/application/json/schema -type FindPetsJSONResponse = []Pet - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/+xXXW9byQ19168gtgXyoly5yaIPemo2TgED3cStd/tOz6UkLubLQ44coe1/Lzj3Srqy", - "ZG+CYvuF9YMNz3A4hzyHHN6UKWLmJXzztrvqrr6ZcVyl5QxgS0U4xSX8ztZnAMrqaQl3j7heU4FbUtFU", - "aAbQk7jCWZv5OxAM2RO8u70B3aBCFRJAyOMBQAGMQJ8HM03QU0hRtKASrAi1FhLgCLoh+JQpmqe33RVI", - "Jscrdmg3GSIqQT6t7qhs2dESNqpZlouFDBA7TotmspgBuBQVnVpkABHDJBJz/wNhaFsUkP0SMLMShj8c", - "XbXdWvyla2YAnh1Foan/dxndhuBNy96Ts4+Pjx22/S6V9WI8LYs/3bz/8PHuw+s33VW30eBnQsWYML+v", - "T13s89lNwsXMs4y6afbNYgC0pjFyAKkhYNkt4S+ktUQB9L5xM+6fkPn3cRHOrGFVUmgMyU6UwkC1/V+F", - "CmyMZOdIBDQdnHzEAEK9kdFzoKg1AIl28D2So4gCSiGnAoJrVmUBwcwU5xDJQdmk6KqAUJgYsAIG0g7e", - "USSMgArrglvuEbCuK80BHTC66rkd7eB9LXjPWguknhP4VCjMIZWIhYDWpECeRnSR3BxcLVIFuAdPTqt0", - "cF1ZIDBoLZllDrn6LUcsdheVZLHPQTk67mtU2GLhKvBTFU0d3ETYoIONgUARguxRCaFnpzVYOm6ikikT", - "FbDnzOI4rgGjWjTH2D2vq8dD5HmDhbTgPolmDyF5EmUCDplKz5apv/IWwxAQen6oGKBntMwUFHiw2Lbk", - "WSGmCJqKpmIp4RXF/nB7B7cFSSiqwaTI4QigloiwTb5qRoUtRYpogIfk2q+AtZiPm3j0vKIyZn2Fjj3L", - "ySXtBvs1P/LrQFKPnozYfm55dFRQLTD728FdlUyxZ8uyRxNPn3wqc1OgkFMTdYuyScWinsOWNuyqR+Co", - "VPoawPM9ldTB96ncM1BlCamf0mDbTdgeHUfGbnaQ/B31jY8qsCKToE/3qbRjlI66KVVLDV2rkIDN7UgB", - "i58D1ZOaGYgHX02NptEObjco5P1QHpnKeLwlu5FMCiusju/rkHbc32N20/Nb8iOBvKVScH56tVULcD8/", - "lGPk+00HPypk8p6ikjxUgpykktXTvpS6lgrc14KV3j6je0/7sFo+5w3IQRyxRgdaWNRigS0rUgd/rOII", - "SFtP6CsfasH6hTjyVLjBGVS8PxBMMxWbhFwNghECri1k8iNbHfy5DkdD8sbbwB7VQUFHKPNDCwKszkpl", - "sBxFOoQ9SmRsNYeaNMkYwcBxfoQylm9k4T1gMQyOtfZsUEUQqu7VNhI53HSStHZfB7dTYlrmRoy5kHIN", - "k/41iKbOJyq3BtyNek7Z6opTvOmXsOLY3x4fjozFsjA+VsPP6/EpVFzLYRGA4xIeKpXdZO3k3TF7mwxW", - "7JUK3E8NCz1ULmQA0AtNdkR3NqGsUgnTVbehgMvJCoDuMi0BS8HdyTorBTk13RuLFo7rs8g8B9avCS3g", - "Zw72stRwTwXSCgpJ9driLe2V/bJgnw2Lh9fjZMdygtr23r6Z7X1LtjY4CfjVm6urV8vnoGfSw6GJjY1W", - "FPUUCubsx0lt8ZOk+DSpl+C/xMyz7NjPbwutlvDqNwuXQk6RospiuEAWt6SvZsdwVli9PhthjfQ527tg", - "D0hJ5ZeK8iXAH+ziAXJOcj63vS+E2ibqSI/GyaXB7cxoP08PIyNc1wG4mdhI7n16pP5SlWNvRT47ypFE", - "v0v9bjm7mMFbUhMy9r39Odw4Oxe0lnpcvpDdl3N7ObMv5fUjPU608F8p/v9PHbfvkMXfuP/HF3yMtDzf", - "7+Dm+pKsn5ihPaA2vYFwXHs6nrr0UH23O2y/9FZx/6Sd2wfVc4m+ubYOngfRr0jd5mLzPtH6v9C7f//t", - "r/L997fhnjwpnWn2ui3/rGb7g9ko0hPpWoe8uQapFsLlDjw4ODbhX0a8wy3/SfV++7J6B4D9/6KIjjt2", - "fNwcPN0emyF6/2k1pfTLXzOzPvB1gvD1qSRyMWkp05M5ivvLU+8lRi9zepGDH2P7WuPehGZSt3GlHRjw", - "L2dPtPZE0LPnUTe9z35mSn8C5yMGmiI5nMX117r6YZfpLKhG90sxudTT5N9AIrh+KUo7cA7tnJVL8/0Z", - "5gbvFMOI4GujHzzt4f8zAAD//6ZcwVZEFgAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/examples/petstore-expanded/stdhttp/Makefile b/experimental/examples/petstore-expanded/stdhttp/Makefile deleted file mode 100644 index 42389f4137..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/experimental/examples/petstore-expanded/stdhttp/go.mod b/experimental/examples/petstore-expanded/stdhttp/go.mod deleted file mode 100644 index e211ad75fb..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/stdhttp - -go 1.24.0 - -require github.com/google/uuid v1.6.0 - -replace github.com/oapi-codegen/oapi-codegen/experimental => ../../../ diff --git a/experimental/examples/petstore-expanded/stdhttp/go.sum b/experimental/examples/petstore-expanded/stdhttp/go.sum deleted file mode 100644 index 7790d7c3e0..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -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= diff --git a/experimental/examples/petstore-expanded/stdhttp/main.go b/experimental/examples/petstore-expanded/stdhttp/main.go deleted file mode 100644 index 9f438a128d..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/main.go +++ /dev/null @@ -1,39 +0,0 @@ -//go:build go1.22 - -// This is an example of implementing the Pet Store from the OpenAPI documentation -// found at: -// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml - -package main - -import ( - "flag" - "log" - "net" - "net/http" - - "github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded/stdhttp/server" -) - -func main() { - port := flag.String("port", "8080", "Port for test HTTP server") - flag.Parse() - - // Create an instance of our handler which satisfies the generated interface - petStore := server.NewPetStore() - - r := http.NewServeMux() - - // We now register our petStore above as the handler for the interface - server.HandlerFromMux(petStore, r) - - s := &http.Server{ - Handler: r, - Addr: net.JoinHostPort("0.0.0.0", *port), - } - - log.Printf("Server listening on %s", s.Addr) - - // And we serve HTTP until the world ends. - log.Fatal(s.ListenAndServe()) -} diff --git a/experimental/examples/petstore-expanded/stdhttp/server/petstore.go b/experimental/examples/petstore-expanded/stdhttp/server/petstore.go deleted file mode 100644 index f05a50f1e6..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/server/petstore.go +++ /dev/null @@ -1,163 +0,0 @@ -//go:build go1.22 - -package server - -import ( - "encoding/json" - "fmt" - "net/http" - "sync" -) - -// 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"` -} - -// 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"` -} - -// Error defines model for Error. -type Error struct { - // Code Error code - Code int32 `json:"code"` - - // Message Error message - Message string `json:"message"` -} - -// PetStore implements the ServerInterface. -type PetStore struct { - Pets map[int64]Pet - NextId int64 - Lock sync.Mutex -} - -// Make sure we conform to ServerInterface -var _ ServerInterface = (*PetStore)(nil) - -// NewPetStore creates a new PetStore. -func NewPetStore() *PetStore { - return &PetStore{ - Pets: make(map[int64]Pet), - NextId: 1000, - } -} - -// sendPetStoreError wraps sending of an error in the Error format. -func sendPetStoreError(w http.ResponseWriter, code int, message string) { - petErr := Error{ - Code: int32(code), - Message: message, - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(petErr) -} - -// FindPets returns all pets, optionally filtered by tags and limited. -func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) { - p.Lock.Lock() - defer p.Lock.Unlock() - - var result []Pet - - for _, pet := range p.Pets { - if params.Tags != nil { - // If we have tags, filter pets by tag - for _, t := range *params.Tags { - if pet.Tag != nil && (*pet.Tag == t) { - result = append(result, pet) - } - } - } else { - // Add all pets if we're not filtering - result = append(result, pet) - } - - if params.Limit != nil { - l := int(*params.Limit) - if len(result) >= l { - // We're at the limit - break - } - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(result) -} - -// AddPet creates a new pet. -func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) { - // We expect a NewPet object in the request body. - var newPet NewPet - if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil { - sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet") - return - } - - // We now have a pet, let's add it to our "database". - p.Lock.Lock() - defer p.Lock.Unlock() - - // We handle pets, not NewPets, which have an additional ID field - var pet Pet - pet.Name = newPet.Name - pet.Tag = newPet.Tag - pet.Id = p.NextId - p.NextId++ - - // Insert into map - p.Pets[pet.Id] = pet - - // Now, we have to return the Pet - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _ = json.NewEncoder(w).Encode(pet) -} - -// FindPetByID returns a pet by ID. -func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - pet, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(pet) -} - -// DeletePet deletes a pet by ID. -func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) { - p.Lock.Lock() - defer p.Lock.Unlock() - - _, found := p.Pets[id] - if !found { - sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id)) - return - } - delete(p.Pets, id) - - w.WriteHeader(http.StatusNoContent) -} diff --git a/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml b/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml deleted file mode 100644 index 4bb9655ead..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/server/server.config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -package: server -output: server.gen.go -generation: - server: std-http - models-package: - path: github.com/oapi-codegen/oapi-codegen/experimental/examples/petstore-expanded - alias: petstore diff --git a/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go b/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go deleted file mode 100644 index a65e2e57e1..0000000000 --- a/experimental/examples/petstore-expanded/stdhttp/server/server.gen.go +++ /dev/null @@ -1,1009 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package server - -import ( - "bytes" - "encoding" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/google/uuid" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Returns all pets - // (GET /pets) - FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) - // Creates a new pet - // (POST /pets) - AddPet(w http.ResponseWriter, r *http.Request) - // Deletes a pet by ID - // (DELETE /pets/{id}) - DeletePet(w http.ResponseWriter, r *http.Request, id int64) - // Returns a pet by ID - // (GET /pets/{id}) - FindPetByID(w http.ResponseWriter, r *http.Request, id int64) -} - -// FindPetsParams defines parameters for FindPets. -type FindPetsParams struct { - // tags (optional) - Tags *[]string `form:"tags" json:"tags"` - // limit (optional) - Limit *int32 `form:"limit" json:"limit"` -} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -// FindPets operation middleware -func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params FindPetsParams - - // ------------- Optional query parameter "tags" ------------- - err = BindFormExplodeParam("tags", false, r.URL.Query(), ¶ms.Tags) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err}) - return - } - - // ------------- Optional query parameter "limit" ------------- - err = BindFormExplodeParam("limit", false, r.URL.Query(), ¶ms.Limit) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPets(w, r, params) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// AddPet operation middleware -func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddPet(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// DeletePet operation middleware -func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeletePet(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// FindPetByID operation middleware -func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "id" ------------- - var id int64 - - err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FindPetByID(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// 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)) - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - -// StdHTTPServerOptions configures the StdHTTP server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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("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) - return m -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/examples/webhook/client/main.go b/experimental/examples/webhook/client/main.go deleted file mode 100644 index 2d12c19acc..0000000000 --- a/experimental/examples/webhook/client/main.go +++ /dev/null @@ -1,150 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/json" - "flag" - "fmt" - "log" - "net" - "net/http" - "time" - - "github.com/google/uuid" - - doorbadge "github.com/oapi-codegen/oapi-codegen/experimental/examples/webhook" -) - -// WebhookReceiver implements doorbadge.WebhookReceiverInterface. -type WebhookReceiver struct{} - -var _ doorbadge.WebhookReceiverInterface = (*WebhookReceiver)(nil) - -func (wr *WebhookReceiver) HandleEnterEventWebhook(w http.ResponseWriter, r *http.Request) { - var person doorbadge.Person - if err := json.NewDecoder(r.Body).Decode(&person); err != nil { - log.Printf("Error decoding enter event: %v", err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - log.Printf("ENTER: %s", person.Name) - w.WriteHeader(http.StatusOK) -} - -func (wr *WebhookReceiver) HandleExitEventWebhook(w http.ResponseWriter, r *http.Request) { - var person doorbadge.Person - if err := json.NewDecoder(r.Body).Decode(&person); err != nil { - log.Printf("Error decoding exit event: %v", err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - log.Printf("EXIT: %s", person.Name) - w.WriteHeader(http.StatusOK) -} - -func registerWebhook(client *http.Client, serverAddr, kind, url string) (uuid.UUID, error) { - body, err := json.Marshal(doorbadge.WebhookRegistration{URL: url}) - if err != nil { - return uuid.UUID{}, err - } - - resp, err := client.Post( - serverAddr+"/api/webhook/"+kind, - "application/json", - bytes.NewReader(body), - ) - if err != nil { - return uuid.UUID{}, err - } - defer func() { _ = resp.Body.Close() }() - - if resp.StatusCode != http.StatusCreated { - return uuid.UUID{}, fmt.Errorf("unexpected status %d", resp.StatusCode) - } - - var regResp doorbadge.WebhookRegistrationResponse - if err := json.NewDecoder(resp.Body).Decode(®Resp); err != nil { - return uuid.UUID{}, err - } - return regResp.ID, nil -} - -func deregisterWebhook(client *http.Client, serverAddr string, id uuid.UUID) error { - req, err := http.NewRequest(http.MethodDelete, serverAddr+"/api/webhook/"+id.String(), nil) - if err != nil { - return err - } - resp, err := client.Do(req) - if err != nil { - return err - } - _ = resp.Body.Close() - return nil -} - -func main() { - serverAddr := flag.String("server", "http://localhost:8080", "Badge reader server address") - duration := flag.Duration("duration", 30*time.Second, "How long to listen for events") - flag.Parse() - - // Start the webhook receiver on an ephemeral port. - receiver := &WebhookReceiver{} - - mux := http.NewServeMux() - mux.Handle("POST /enter", doorbadge.EnterEventWebhookHandler(receiver, nil)) - mux.Handle("POST /exit", doorbadge.ExitEventWebhookHandler(receiver, nil)) - - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - log.Fatalf("Failed to listen: %v", err) - } - callbackPort := listener.Addr().(*net.TCPAddr).Port - baseURL := fmt.Sprintf("http://localhost:%d", callbackPort) - log.Printf("Webhook receiver listening on port %d", callbackPort) - - srv := &http.Server{Handler: mux} - go func() { - if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed { - log.Printf("Webhook server stopped: %v", err) - } - }() - - // Register webhooks for both event kinds. - client := &http.Client{} - - kinds := [2]string{"enterEvent", "exitEvent"} - urls := [2]string{baseURL + "/enter", baseURL + "/exit"} - var registrationIDs [2]uuid.UUID - - for i, kind := range kinds { - id, err := registerWebhook(client, *serverAddr, kind, urls[i]) - if err != nil { - log.Fatalf("Failed to register %s webhook: %v", kind, err) - } - registrationIDs[i] = id - log.Printf("Registered %s webhook: id=%s url=%s", kind, id, urls[i]) - } - - log.Printf("Listening for events for %s...", *duration) - - // Wait for the specified duration. - time.Sleep(*duration) - - // Deregister webhooks cleanly. - log.Printf("Duration elapsed, deregistering webhooks...") - for i, id := range registrationIDs { - if err := deregisterWebhook(client, *serverAddr, id); err != nil { - log.Printf("Failed to deregister %s webhook: %v", kinds[i], err) - continue - } - log.Printf("Deregistered %s webhook: id=%s", kinds[i], id) - } - - // Shut down the local webhook server. - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) - defer cancel() - _ = srv.Shutdown(ctx) - - log.Printf("Done!") -} diff --git a/experimental/examples/webhook/config.yaml b/experimental/examples/webhook/config.yaml deleted file mode 100644 index 6a95d87ee1..0000000000 --- a/experimental/examples/webhook/config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: doorbadge -output: doorbadge.gen.go -generation: - webhook-initiator: true - webhook-receiver: true - server: std-http diff --git a/experimental/examples/webhook/doc.go b/experimental/examples/webhook/doc.go deleted file mode 100644 index ee6d3b6920..0000000000 --- a/experimental/examples/webhook/doc.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:generate go run github.com/oapi-codegen/oapi-codegen/experimental/cmd/oapi-codegen -config config.yaml door-badge-reader.yaml - -// Package doorbadge provides an example of OpenAPI 3.1 webhooks. -// A door badge reader server generates random enter/exit events and -// notifies registered webhook listeners. -// -// You can run the example by running these two commands in parallel: -// -// go run ./server --port 8080 -// go run ./client --server http://localhost:8080 -// -// You can run multiple clients and they will all get the notifications -package doorbadge diff --git a/experimental/examples/webhook/door-badge-reader.yaml b/experimental/examples/webhook/door-badge-reader.yaml deleted file mode 100644 index ac37ce40dd..0000000000 --- a/experimental/examples/webhook/door-badge-reader.yaml +++ /dev/null @@ -1,139 +0,0 @@ -openapi: "3.1.0" -info: - version: 1.0.0 - title: Door Badge Reader - description: | - A door badge reader service that demonstrates OpenAPI 3.1 webhooks. - Clients register for enterEvent and exitEvent webhooks. The server - randomly generates badge events and notifies all registered listeners. - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html -paths: - /api/webhook/{kind}: - post: - summary: Register a webhook - description: | - Registers a webhook for the given event kind. The server will POST - to the provided URL whenever an event of that kind occurs. - operationId: RegisterWebhook - parameters: - - name: kind - in: path - required: true - schema: - type: string - enum: - - enterEvent - - exitEvent - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/WebhookRegistration' - responses: - '201': - description: Webhook registered - content: - application/json: - schema: - $ref: '#/components/schemas/WebhookRegistrationResponse' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /api/webhook/{id}: - delete: - summary: Deregister a webhook - description: Removes a previously registered webhook by its ID. - operationId: DeregisterWebhook - parameters: - - name: id - in: path - required: true - schema: - type: string - format: uuid - responses: - '204': - description: Webhook deregistered - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' -webhooks: - enterEvent: - post: - summary: Person entered the building - operationId: EnterEvent - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Person' - responses: - '200': - description: Event received - exitEvent: - post: - summary: Person exited the building - operationId: ExitEvent - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Person' - responses: - '200': - description: Event received -components: - schemas: - WebhookRegistration: - type: object - required: - - url - properties: - url: - type: string - format: uri - description: URL to receive webhook events - - WebhookRegistrationResponse: - type: object - required: - - id - properties: - id: - type: string - format: uuid - description: Unique identifier for this webhook registration - - Person: - type: object - required: - - name - properties: - name: - type: string - description: Name of the person who badged in or out - - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message diff --git a/experimental/examples/webhook/doorbadge.gen.go b/experimental/examples/webhook/doorbadge.gen.go deleted file mode 100644 index 702d74db62..0000000000 --- a/experimental/examples/webhook/doorbadge.gen.go +++ /dev/null @@ -1,1069 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package doorbadge - -import ( - "bytes" - "compress/gzip" - "context" - "encoding" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "time" - - "github.com/google/uuid" -) - -// #/components/schemas/WebhookRegistration -type WebhookRegistration struct { - URL string `json:"url" form:"url"` // URL to receive webhook events -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *WebhookRegistration) ApplyDefaults() { -} - -// #/components/schemas/WebhookRegistrationResponse -type WebhookRegistrationResponse struct { - ID UUID `json:"id" form:"id"` // Unique identifier for this webhook registration -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *WebhookRegistrationResponse) ApplyDefaults() { -} - -// #/components/schemas/Person -type Person struct { - Name string `json:"name" form:"name"` // Name of the person who badged in or out -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Person) ApplyDefaults() { -} - -// #/components/schemas/Error -type Error struct { - Code int32 `json:"code" form:"code"` // Error code - Message string `json:"message" form:"message"` // Error message -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Error) ApplyDefaults() { -} - -// #/paths//api/webhook/{kind}/post/parameters/0/schema -type PostAPIWebhookKindParameter string - -const ( - PostAPIWebhookKindParameter_enterEvent PostAPIWebhookKindParameter = "enterEvent" - PostAPIWebhookKindParameter_exitEvent PostAPIWebhookKindParameter = "exitEvent" -) - -type UUID = uuid.UUID - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/9RWTY/bNhC961cM0gI+RfLu9qTbJuvDAkGycFL0TItjaxKJZIaUvEbb/16Q1GdX3l0D", - "RZv6ZEnDmfceh4+jDSphKIc3N+lVun6TkNrrPAFokS1plcNVuk7XCYAjV2EOd1ozvBPygLBFIZETAIm2", - "YDIuxP+RAADcgvSBuxDIIRAscksFgiuFA4m1VtaxcGjhk0F1+3APN+kVHHFXav3NpiHP+4pQOQuMB7IO", - "GfaaAZVD3rSoHAglAR/JxadhLXwpMdQL+ABYKKnr6gQHVBhrRmjYhvQ+jdKO9oQWRFUN9VBC5f8o5ICo", - "ogKVxTxkVaLGHG6NKEqE66ASQMNVDqVzxuZZdjweUxG+p5oPWbfaZh/u328+ft68vU7XaenqKjHCldZn", - "zYShrOOR/f6NlPwzFjPauvgPwDZ1LfiUw7aXRfTcu4iFLfG/Pt6OC4KirkQ4UIsqCgK+7lREOFJVwcOn", - "z1+GVE6HVYZ1SxIl/Lr9AMcSFfpw0SfS+7jdPiHoomi421gAbfxOkFb3ciTy24yFESxq9Hjzoe7bTnaf", - "cXgJQCoHL+LkFeP3hhhlDo4bnHywRYm1yCdvANzJYA7WManD7AOqpp6HegxjCz791LdjMsJA695peRrz", - "nMFWaOVQuWk9YUxFRRAq+2q1mmNZogLwM+M+h9VPWaFro5Vv8SxG2qxTOAoeN2A1ILVG+/4c862u11er", - "afpZY3W5JqdlErnA5SU25/hczGjbMVklI+69aCp3lkqj8NFg4VACMmv+L4hsfOHVExOg3gIkVujwiQnc", - "Ib/KBrZY69b7GxjGlnRjq9PU6HpD2J2AnIX7u8WTOlZ7/Vmlf+Wk7jXXwuXQNEO95Y7+5eWOlrjQ0/+j", - "HupvQr949KpnbpIHZKtVjEUZrH3XUCVHkWddsPm7//1gLhfpPG9s6/NtEMcJxgKpDQ0wmPorJHwk9xoF", - "f+xr4p8VcCzgV3Q14uIF9+6zxpOud1+xmKoUBJl4TMNV70HsJXY0xennseRF9xi8g+kcJT/gON1zGtwy", - "TpDJOS79TXQhp8HBliiRvIRRM3PfOSVF3xsEkqjC7MvdMEh2oMcTLpFk7IwL+fh74BlG4Zp4mdMM/EdR", - "Y5wvEUw8esdSx7leAinQDLpxEXSwxQsxF1ri5LFGa8XhORZ+wVMWpBwekBe2hpS7uT57gjziOYYOwaVC", - "xUw9/L8CAAD//+XREy3yDQAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Deregister a webhook - // (DELETE /api/webhook/{id}) - DeregisterWebhook(w http.ResponseWriter, r *http.Request, id uuid.UUID) - // Register a webhook - // (POST /api/webhook/{kind}) - RegisterWebhook(w http.ResponseWriter, r *http.Request, kind string) -} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -// DeregisterWebhook operation middleware -func (siw *ServerInterfaceWrapper) DeregisterWebhook(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "id" ------------- - var id uuid.UUID - - err = BindSimpleParam("id", ParamLocationPath, r.PathValue("id"), &id) - 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.DeregisterWebhook(w, r, id) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// RegisterWebhook operation middleware -func (siw *ServerInterfaceWrapper) RegisterWebhook(w http.ResponseWriter, r *http.Request) { - var err error - - // ------------- Path parameter "kind" ------------- - var kind string - - err = BindSimpleParam("kind", ParamLocationPath, r.PathValue("kind"), &kind) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "kind", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RegisterWebhook(w, r, kind) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// 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)) - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - -// StdHTTPServerOptions configures the StdHTTP server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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("DELETE "+options.BaseURL+"/api/webhook/{id}", wrapper.DeregisterWebhook) - m.HandleFunc("POST "+options.BaseURL+"/api/webhook/{kind}", wrapper.RegisterWebhook) - return m -} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -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) -} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} - -type EnterEventJSONRequestBody = Person - -type ExitEventJSONRequestBody = Person - -// RequestEditorFn is the function signature for the RequestEditor callback function. -// It may already be defined if client code is also generated; this is a compatible redeclaration. -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// HttpRequestDoer performs HTTP requests. -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// WebhookInitiator sends webhook requests to target URLs. -// Unlike Client, it has no stored base URL — the full target URL is provided per-call. -type WebhookInitiator struct { - // 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 -} - -// WebhookInitiatorOption allows setting custom parameters during construction. -type WebhookInitiatorOption func(*WebhookInitiator) error - -// NewWebhookInitiator creates a new WebhookInitiator with reasonable defaults. -func NewWebhookInitiator(opts ...WebhookInitiatorOption) (*WebhookInitiator, error) { - initiator := WebhookInitiator{} - for _, o := range opts { - if err := o(&initiator); err != nil { - return nil, err - } - } - if initiator.Client == nil { - initiator.Client = &http.Client{} - } - return &initiator, nil -} - -// WithWebhookHTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func WithWebhookHTTPClient(doer HttpRequestDoer) WebhookInitiatorOption { - return func(p *WebhookInitiator) error { - p.Client = doer - return nil - } -} - -// WithWebhookRequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func WithWebhookRequestEditorFn(fn RequestEditorFn) WebhookInitiatorOption { - return func(p *WebhookInitiator) error { - p.RequestEditors = append(p.RequestEditors, fn) - return nil - } -} - -func (p *WebhookInitiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range p.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 -} - -// WebhookInitiatorInterface is the interface specification for the webhook initiator. -type WebhookInitiatorInterface interface { - // EnterEventWithBody sends a POST webhook request - EnterEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - EnterEvent(ctx context.Context, targetURL string, body EnterEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) - // ExitEventWithBody sends a POST webhook request - ExitEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - ExitEvent(ctx context.Context, targetURL string, body ExitEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -// EnterEventWithBody sends a POST webhook request -// Person entered the building -func (p *WebhookInitiator) EnterEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewEnterEventWebhookRequestWithBody(targetURL, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// EnterEvent sends a POST webhook request with JSON body -func (p *WebhookInitiator) EnterEvent(ctx context.Context, targetURL string, body EnterEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewEnterEventWebhookRequest(targetURL, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// ExitEventWithBody sends a POST webhook request -// Person exited the building -func (p *WebhookInitiator) ExitEventWithBody(ctx context.Context, targetURL string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewExitEventWebhookRequestWithBody(targetURL, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// ExitEvent sends a POST webhook request with JSON body -func (p *WebhookInitiator) ExitEvent(ctx context.Context, targetURL string, body ExitEventJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewExitEventWebhookRequest(targetURL, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} - -// NewEnterEventWebhookRequest creates a POST request for the webhook with application/json body -func NewEnterEventWebhookRequest(targetURL string, body EnterEventJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewEnterEventWebhookRequestWithBody(targetURL, "application/json", bodyReader) -} - -// NewEnterEventWebhookRequestWithBody creates a POST request for the webhook with any body -func NewEnterEventWebhookRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - parsedURL, err := url.Parse(targetURL) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", parsedURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// NewExitEventWebhookRequest creates a POST request for the webhook with application/json body -func NewExitEventWebhookRequest(targetURL string, body ExitEventJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewExitEventWebhookRequestWithBody(targetURL, "application/json", bodyReader) -} - -// NewExitEventWebhookRequestWithBody creates a POST request for the webhook with any body -func NewExitEventWebhookRequestWithBody(targetURL string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - parsedURL, err := url.Parse(targetURL) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", parsedURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -// WebhookHttpError represents an HTTP error response. -// The type parameter E is the type of the parsed error body. -type WebhookHttpError[E any] struct { - StatusCode int - Body E - RawBody []byte -} - -func (e *WebhookHttpError[E]) Error() string { - return fmt.Sprintf("HTTP %d", e.StatusCode) -} - -// SimpleWebhookInitiator wraps WebhookInitiator with typed responses for operations that have -// unambiguous response types. Methods return the success type directly, -// and HTTP errors are returned as *WebhookHttpError[E] where E is the error type. -type SimpleWebhookInitiator struct { - *WebhookInitiator -} - -// NewSimpleWebhookInitiator creates a new SimpleWebhookInitiator which wraps a WebhookInitiator. -func NewSimpleWebhookInitiator(opts ...WebhookInitiatorOption) (*SimpleWebhookInitiator, error) { - initiator, err := NewWebhookInitiator(opts...) - if err != nil { - return nil, err - } - return &SimpleWebhookInitiator{WebhookInitiator: initiator}, nil -} - -// WebhookReceiverInterface represents handlers for receiving webhook requests. -type WebhookReceiverInterface interface { - // Person entered the building - // HandleEnterEventWebhook handles the POST webhook request. - HandleEnterEventWebhook(w http.ResponseWriter, r *http.Request) - // Person exited the building - // HandleExitEventWebhook handles the POST webhook request. - HandleExitEventWebhook(w http.ResponseWriter, r *http.Request) -} - -// WebhookReceiverMiddlewareFunc is a middleware function for webhook receiver handlers. -type WebhookReceiverMiddlewareFunc func(http.Handler) http.Handler - -// EnterEventWebhookHandler returns an http.Handler for the EnterEvent webhook. -// The caller is responsible for registering this handler at the appropriate path. -func EnterEventWebhookHandler(si WebhookReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...WebhookReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.HandleEnterEventWebhook(w, r) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} - -// ExitEventWebhookHandler returns an http.Handler for the ExitEvent webhook. -// The caller is responsible for registering this handler at the appropriate path. -func ExitEventWebhookHandler(si WebhookReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...WebhookReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.HandleExitEventWebhook(w, r) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} diff --git a/experimental/examples/webhook/server/main.go b/experimental/examples/webhook/server/main.go deleted file mode 100644 index 8476aab7a8..0000000000 --- a/experimental/examples/webhook/server/main.go +++ /dev/null @@ -1,186 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "flag" - "log" - "math/rand/v2" - "net" - "net/http" - "sync" - "time" - - "github.com/google/uuid" - - doorbadge "github.com/oapi-codegen/oapi-codegen/experimental/examples/webhook" -) - -var names = []string{ - "Alice", "Bob", "Charlie", "Diana", "Eve", - "Frank", "Grace", "Hank", "Iris", "Jack", -} - -type webhookEntry struct { - id uuid.UUID - url string - kind string -} - -// BadgeReader implements doorbadge.ServerInterface. -type BadgeReader struct { - initiator *doorbadge.WebhookInitiator - - mu sync.Mutex - webhooks map[uuid.UUID]webhookEntry -} - -var _ doorbadge.ServerInterface = (*BadgeReader)(nil) - -func NewBadgeReader() *BadgeReader { - initiator, err := doorbadge.NewWebhookInitiator() - if err != nil { - log.Fatalf("Failed to create webhook initiator: %v", err) - } - return &BadgeReader{ - initiator: initiator, - webhooks: make(map[uuid.UUID]webhookEntry), - } -} - -func sendError(w http.ResponseWriter, code int, message string) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(doorbadge.Error{ - Code: int32(code), - Message: message, - }) -} - -func (br *BadgeReader) RegisterWebhook(w http.ResponseWriter, r *http.Request, kind string) { - var req doorbadge.WebhookRegistration - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - sendError(w, http.StatusBadRequest, "Invalid request body: "+err.Error()) - return - } - - if kind != "enterEvent" && kind != "exitEvent" { - sendError(w, http.StatusBadRequest, "Invalid webhook kind: "+kind) - return - } - - id := uuid.New() - entry := webhookEntry{id: id, url: req.URL, kind: kind} - - br.mu.Lock() - br.webhooks[id] = entry - br.mu.Unlock() - - log.Printf("Registered webhook: id=%s kind=%s url=%s", id, kind, req.URL) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _ = json.NewEncoder(w).Encode(doorbadge.WebhookRegistrationResponse{ID: id}) -} - -func (br *BadgeReader) DeregisterWebhook(w http.ResponseWriter, r *http.Request, id uuid.UUID) { - br.mu.Lock() - entry, ok := br.webhooks[id] - delete(br.webhooks, id) - br.mu.Unlock() - - if !ok { - sendError(w, http.StatusNotFound, "Webhook not found: "+id.String()) - return - } - - log.Printf("Deregistered webhook: id=%s kind=%s url=%s", id, entry.kind, entry.url) - w.WriteHeader(http.StatusNoContent) -} - -// generateEvents picks a random name and event kind every second and notifies webhooks. -func (br *BadgeReader) generateEvents(ctx context.Context) { - ticker := time.NewTicker(1 * time.Second) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - name := names[rand.IntN(len(names))] - kind := "enterEvent" - if rand.IntN(2) == 0 { - kind = "exitEvent" - } - - person := doorbadge.Person{Name: name} - - br.mu.Lock() - targets := make([]webhookEntry, 0) - for _, entry := range br.webhooks { - if entry.kind == kind { - targets = append(targets, entry) - } - } - br.mu.Unlock() - - if len(targets) == 0 { - continue - } - - log.Printf("Event: %s %s (%d webhooks)", kind, name, len(targets)) - - for _, target := range targets { - var resp *http.Response - var err error - - switch kind { - case "enterEvent": - resp, err = br.initiator.EnterEvent(ctx, target.url, person) - case "exitEvent": - resp, err = br.initiator.ExitEvent(ctx, target.url, person) - } - - if err != nil { - log.Printf("Webhook %s failed: %v — removing", target.id, err) - br.mu.Lock() - delete(br.webhooks, target.id) - br.mu.Unlock() - continue - } - _ = resp.Body.Close() - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - log.Printf("Webhook %s returned %d — removing", target.id, resp.StatusCode) - br.mu.Lock() - delete(br.webhooks, target.id) - br.mu.Unlock() - } - } - } - } -} - -func main() { - port := flag.String("port", "8080", "Port for HTTP server") - flag.Parse() - - reader := NewBadgeReader() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go reader.generateEvents(ctx) - - mux := http.NewServeMux() - doorbadge.HandlerFromMux(reader, mux) - - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Printf("%s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) - mux.ServeHTTP(w, r) - }) - - addr := net.JoinHostPort("0.0.0.0", *port) - log.Printf("Door Badge Reader server listening on %s", addr) - log.Fatal(http.ListenAndServe(addr, handler)) -} diff --git a/experimental/go.mod b/experimental/go.mod deleted file mode 100644 index 70784976bf..0000000000 --- a/experimental/go.mod +++ /dev/null @@ -1,27 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/experimental - -go 1.24.0 - -require ( - github.com/google/uuid v1.6.0 - github.com/pb33f/libopenapi v0.33.5 - github.com/stretchr/testify v1.11.1 - go.yaml.in/yaml/v4 v4.0.0-rc.4 // required by libopenapi for Extensions type - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - golang.org/x/text v0.33.0 - golang.org/x/tools v0.41.0 -) - -require ( - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pb33f/jsonpath v0.7.1 // indirect - github.com/pb33f/ordered-map/v2 v2.3.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/sync v0.19.0 // indirect -) diff --git a/experimental/go.sum b/experimental/go.sum deleted file mode 100644 index 28075cb106..0000000000 --- a/experimental/go.sum +++ /dev/null @@ -1,41 +0,0 @@ -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/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/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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/pb33f/jsonpath v0.7.1 h1:dEp6oIZuJbpDSyuHAl9m7GonoDW4M20BcD5vT0tPYRE= -github.com/pb33f/jsonpath v0.7.1/go.mod h1:zBV5LJW4OQOPatmQE2QdKpGQJvhDTlE5IEj6ASaRNTo= -github.com/pb33f/libopenapi v0.33.5 h1:AzILVrOzMaawLFhQENmwmn7h/TIDH2QEgUd0PfxS2xE= -github.com/pb33f/libopenapi v0.33.5/go.mod h1:e/dmd2Pf1nkjqkI0r7guFSyt9T5V0IIQKgs0L6B/3b0= -github.com/pb33f/ordered-map/v2 v2.3.0 h1:k2OhVEQkhTCQMhAicQ3Z6iInzoZNQ7L9MVomwKBZ5WQ= -github.com/pb33f/ordered-map/v2 v2.3.0/go.mod h1:oe5ue+6ZNhy7QN9cPZvPA23Hx0vMHnNVeMg4fGdCANw= -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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U= -go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/experimental/internal/codegen/clientgen.go b/experimental/internal/codegen/clientgen.go deleted file mode 100644 index 759d9e2da1..0000000000 --- a/experimental/internal/codegen/clientgen.go +++ /dev/null @@ -1,349 +0,0 @@ -package codegen - -import ( - "bytes" - "fmt" - "strings" - "text/template" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// ClientGenerator generates client code from operation descriptors. -type ClientGenerator struct { - tmpl *template.Template - schemaIndex map[string]*SchemaDescriptor - generateSimple bool - modelsPackage *ModelsPackage -} - -// NewClientGenerator creates a new client generator. -// modelsPackage can be nil if models are in the same package. -func NewClientGenerator(schemaIndex map[string]*SchemaDescriptor, generateSimple bool, modelsPackage *ModelsPackage) (*ClientGenerator, error) { - tmpl := template.New("client").Funcs(templates.Funcs()).Funcs(clientFuncs(schemaIndex, modelsPackage)) - - // Parse client templates - for _, ct := range templates.ClientTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + ct.Template) - if err != nil { - return nil, err - } - _, err = tmpl.New(ct.Name).Parse(string(content)) - if err != nil { - return nil, err - } - } - - // Parse shared templates (param_types is shared with server) - for _, st := range templates.SharedServerTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + st.Template) - if err != nil { - return nil, err - } - _, err = tmpl.New(st.Name).Parse(string(content)) - if err != nil { - return nil, err - } - } - - return &ClientGenerator{ - tmpl: tmpl, - schemaIndex: schemaIndex, - generateSimple: generateSimple, - modelsPackage: modelsPackage, - }, nil -} - -// clientFuncs returns template functions specific to client generation. -func clientFuncs(schemaIndex map[string]*SchemaDescriptor, modelsPackage *ModelsPackage) template.FuncMap { - return template.FuncMap{ - "pathFmt": pathFmt, - "isSimpleOperation": isSimpleOperation, - "simpleOperationSuccessResponse": simpleOperationSuccessResponse, - "errorResponseForOperation": errorResponseForOperation, - "goTypeForContent": func(content *ResponseContentDescriptor) string { - return goTypeForContent(content, schemaIndex, modelsPackage) - }, - "modelsPkg": func() string { - return modelsPackage.Prefix() - }, - } -} - -// pathFmt converts a path with {param} placeholders to a format string. -// Example: "/pets/{petId}" -> "/pets/%s" -func pathFmt(path string) string { - result := path - for { - start := strings.Index(result, "{") - if start == -1 { - break - } - end := strings.Index(result, "}") - if end == -1 { - break - } - result = result[:start] + "%s" + result[end+1:] - } - return result -} - -// isSimpleOperation returns true if an operation has a single JSON success response type. -// "Simple" operations can have typed wrapper methods in SimpleClient. -func isSimpleOperation(op *OperationDescriptor) bool { - // Must have responses - if len(op.Responses) == 0 { - return false - } - - // Count success responses (2xx or default that could be success) - var successResponses []*ResponseDescriptor - for _, r := range op.Responses { - if strings.HasPrefix(r.StatusCode, "2") { - successResponses = append(successResponses, r) - } - } - - // Must have exactly one success response - if len(successResponses) != 1 { - return false - } - - success := successResponses[0] - - // Must have at least one content type and exactly one JSON content type - // (i.e., if there are multiple content types, we can't have a simple typed response) - if len(success.Contents) == 0 { - return false - } - if len(success.Contents) != 1 { - return false - } - - // The single content type must be JSON - return success.Contents[0].IsJSON -} - -// simpleOperationSuccessResponse returns the single success response for a simple operation. -func simpleOperationSuccessResponse(op *OperationDescriptor) *ResponseDescriptor { - for _, r := range op.Responses { - if strings.HasPrefix(r.StatusCode, "2") { - return r - } - } - return nil -} - -// errorResponseForOperation returns the error response (default or 4xx/5xx) if one exists. -func errorResponseForOperation(op *OperationDescriptor) *ResponseDescriptor { - // First, look for a default response - for _, r := range op.Responses { - if r.StatusCode == "default" { - if len(r.Contents) > 0 && r.Contents[0].IsJSON { - return r - } - } - } - // Then look for a 4xx or 5xx response - for _, r := range op.Responses { - if strings.HasPrefix(r.StatusCode, "4") || strings.HasPrefix(r.StatusCode, "5") { - if len(r.Contents) > 0 && r.Contents[0].IsJSON { - return r - } - } - } - return nil -} - -// goTypeForContent returns the Go type for a response content descriptor. -// If modelsPackage is set, type names are prefixed with the package name. -func goTypeForContent(content *ResponseContentDescriptor, schemaIndex map[string]*SchemaDescriptor, modelsPackage *ModelsPackage) string { - if content == nil || content.Schema == nil { - return "interface{}" - } - - pkgPrefix := modelsPackage.Prefix() - - // If the schema has a reference, look it up - if content.Schema.Ref != "" { - if target, ok := schemaIndex[content.Schema.Ref]; ok { - return pkgPrefix + target.ShortName - } - } - - // Check if this is an array schema with items that have a reference - if content.Schema.Schema != nil && content.Schema.Schema.Items != nil { - itemProxy := content.Schema.Schema.Items.A - if itemProxy != nil && itemProxy.IsReference() { - ref := itemProxy.GetReference() - if target, ok := schemaIndex[ref]; ok { - return "[]" + pkgPrefix + target.ShortName - } - } - } - - // If the schema has a short name, use it - if content.Schema.ShortName != "" { - return pkgPrefix + content.Schema.ShortName - } - - // Fall back to the stable name - if content.Schema.StableName != "" { - return pkgPrefix + content.Schema.StableName - } - - // Try to derive from the schema itself - if content.Schema.Schema != nil { - return schemaToGoType(content.Schema.Schema) - } - - return "interface{}" -} - -// GenerateBase generates the base client types and helpers. -func (g *ClientGenerator) GenerateBase() (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "base", nil); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateInterface generates the ClientInterface. -func (g *ClientGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "interface", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateMethods generates the Client methods. -func (g *ClientGenerator) GenerateMethods(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "methods", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateRequestBuilders generates the request builder functions. -func (g *ClientGenerator) GenerateRequestBuilders(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "request_builders", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateSimple generates the SimpleClient with typed responses. -func (g *ClientGenerator) GenerateSimple(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "simple", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateParamTypes generates the parameter struct types. -func (g *ClientGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateRequestBodyTypes generates type aliases for request bodies. -func (g *ClientGenerator) GenerateRequestBodyTypes(ops []*OperationDescriptor) string { - var buf bytes.Buffer - pkgPrefix := g.modelsPackage.Prefix() - - for _, op := range ops { - for _, body := range op.Bodies { - if !body.IsJSON { - continue - } - // Get the underlying type for this request body - var targetType string - if body.Schema != nil { - if body.Schema.Ref != "" { - // Reference to a component schema - if target, ok := g.schemaIndex[body.Schema.Ref]; ok { - targetType = pkgPrefix + target.ShortName - } - } else if body.Schema.ShortName != "" { - targetType = pkgPrefix + body.Schema.ShortName - } - } - if targetType == "" { - targetType = "interface{}" - } - - // Generate type alias: type addPetJSONRequestBody = models.NewPet - buf.WriteString(fmt.Sprintf("type %s = %s\n\n", body.GoTypeName, targetType)) - } - } - - return buf.String() -} - -// GenerateClient generates the complete client code. -func (g *ClientGenerator) GenerateClient(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - - // Generate request body type aliases first - bodyTypes := g.GenerateRequestBodyTypes(ops) - buf.WriteString(bodyTypes) - - // Generate base client - base, err := g.GenerateBase() - if err != nil { - return "", fmt.Errorf("generating base client: %w", err) - } - buf.WriteString(base) - buf.WriteString("\n") - - // Generate interface - iface, err := g.GenerateInterface(ops) - if err != nil { - return "", fmt.Errorf("generating client interface: %w", err) - } - buf.WriteString(iface) - buf.WriteString("\n") - - // Generate param types - paramTypes, err := g.GenerateParamTypes(ops) - if err != nil { - return "", fmt.Errorf("generating param types: %w", err) - } - buf.WriteString(paramTypes) - buf.WriteString("\n") - - // Generate methods - methods, err := g.GenerateMethods(ops) - if err != nil { - return "", fmt.Errorf("generating client methods: %w", err) - } - buf.WriteString(methods) - buf.WriteString("\n") - - // Generate request builders - builders, err := g.GenerateRequestBuilders(ops) - if err != nil { - return "", fmt.Errorf("generating request builders: %w", err) - } - buf.WriteString(builders) - buf.WriteString("\n") - - // Generate simple client if requested - if g.generateSimple { - simple, err := g.GenerateSimple(ops) - if err != nil { - return "", fmt.Errorf("generating simple client: %w", err) - } - buf.WriteString(simple) - } - - return buf.String(), nil -} diff --git a/experimental/internal/codegen/clientgen_test.go b/experimental/internal/codegen/clientgen_test.go deleted file mode 100644 index cb5d6961b5..0000000000 --- a/experimental/internal/codegen/clientgen_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package codegen - -import ( - "os" - "testing" - - "github.com/pb33f/libopenapi" - "github.com/stretchr/testify/require" -) - -func TestClientGenerator(t *testing.T) { - // Read the petstore spec - specPath := "../../examples/petstore-expanded/petstore-expanded.yaml" - specData, err := os.ReadFile(specPath) - require.NoError(t, err, "Failed to read petstore spec") - - // Parse the spec - doc, err := libopenapi.NewDocument(specData) - require.NoError(t, err, "Failed to parse petstore spec") - - // Gather schemas to build schema index - contentTypeMatcher := NewContentTypeMatcher(DefaultContentTypes()) - schemas, err := GatherSchemas(doc, contentTypeMatcher) - require.NoError(t, err, "Failed to gather schemas") - - // Compute names for schemas - converter := NewNameConverter(NameMangling{}, NameSubstitutions{}) - contentTypeNamer := NewContentTypeShortNamer(DefaultContentTypeShortNames()) - ComputeSchemaNames(schemas, converter, contentTypeNamer) - - // Build schema index - key by Path.String() for component schemas - schemaIndex := make(map[string]*SchemaDescriptor) - for _, s := range schemas { - schemaIndex[s.Path.String()] = s - } - - // Create param tracker - paramTracker := NewParamUsageTracker() - - // Gather operations - ops, err := GatherOperations(doc, paramTracker) - require.NoError(t, err, "Failed to gather operations") - require.Len(t, ops, 4, "Expected 4 operations") - - // Log operations for debugging - // Verify we have the expected operations - operationIDs := make([]string, 0, len(ops)) - for _, op := range ops { - operationIDs = append(operationIDs, op.GoOperationID) - } - t.Logf("Operations: %v", operationIDs) - - // Generate client code - gen, err := NewClientGenerator(schemaIndex, true, nil) - require.NoError(t, err, "Failed to create client generator") - - clientCode, err := gen.GenerateClient(ops) - require.NoError(t, err, "Failed to generate client code") - require.NotEmpty(t, clientCode, "Generated client code should not be empty") - - t.Logf("Generated client code:\n%s", clientCode) - - // Verify key components are present - require.Contains(t, clientCode, "type Client struct") - require.Contains(t, clientCode, "NewClient") - require.Contains(t, clientCode, "type ClientInterface interface") - require.Contains(t, clientCode, "FindPets") - require.Contains(t, clientCode, "AddPet") - require.Contains(t, clientCode, "DeletePet") - require.Contains(t, clientCode, "FindPetByID") - - // Verify request builders - require.Contains(t, clientCode, "NewFindPetsRequest") - require.Contains(t, clientCode, "NewAddPetRequest") - require.Contains(t, clientCode, "NewDeletePetRequest") - require.Contains(t, clientCode, "NewFindPetByIDRequest") - - // Verify SimpleClient - require.Contains(t, clientCode, "type SimpleClient struct") - require.Contains(t, clientCode, "NewSimpleClient") -} - -func TestIsSimpleOperation(t *testing.T) { - tests := []struct { - name string - op *OperationDescriptor - expected bool - }{ - { - name: "simple operation with single JSON 200 response", - op: &OperationDescriptor{ - Responses: []*ResponseDescriptor{ - { - StatusCode: "200", - Contents: []*ResponseContentDescriptor{ - {ContentType: "application/json", IsJSON: true}, - }, - }, - }, - }, - expected: true, - }, - { - name: "not simple - multiple success responses", - op: &OperationDescriptor{ - Responses: []*ResponseDescriptor{ - { - StatusCode: "200", - Contents: []*ResponseContentDescriptor{ - {ContentType: "application/json", IsJSON: true}, - }, - }, - { - StatusCode: "201", - Contents: []*ResponseContentDescriptor{ - {ContentType: "application/json", IsJSON: true}, - }, - }, - }, - }, - expected: false, - }, - { - name: "not simple - multiple content types", - op: &OperationDescriptor{ - Responses: []*ResponseDescriptor{ - { - StatusCode: "200", - Contents: []*ResponseContentDescriptor{ - {ContentType: "application/json", IsJSON: true}, - {ContentType: "application/xml", IsJSON: false}, - }, - }, - }, - }, - expected: false, - }, - { - name: "not simple - no JSON content", - op: &OperationDescriptor{ - Responses: []*ResponseDescriptor{ - { - StatusCode: "200", - Contents: []*ResponseContentDescriptor{ - {ContentType: "text/plain", IsJSON: false}, - }, - }, - }, - }, - expected: false, - }, - { - name: "not simple - no responses", - op: &OperationDescriptor{}, - expected: false, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - result := isSimpleOperation(tc.op) - if result != tc.expected { - t.Errorf("isSimpleOperation() = %v, expected %v", result, tc.expected) - } - }) - } -} - -func TestPathFmt(t *testing.T) { - tests := []struct { - path string - expected string - }{ - {"/pets", "/pets"}, - {"/pets/{petId}", "/pets/%s"}, - {"/pets/{petId}/photos/{photoId}", "/pets/%s/photos/%s"}, - {"/users/{userId}/posts/{postId}/comments/{commentId}", "/users/%s/posts/%s/comments/%s"}, - } - - for _, tc := range tests { - t.Run(tc.path, func(t *testing.T) { - result := pathFmt(tc.path) - if result != tc.expected { - t.Errorf("pathFmt(%q) = %q, expected %q", tc.path, result, tc.expected) - } - }) - } -} diff --git a/experimental/internal/codegen/codegen.go b/experimental/internal/codegen/codegen.go deleted file mode 100644 index 5b6fdff894..0000000000 --- a/experimental/internal/codegen/codegen.go +++ /dev/null @@ -1,1101 +0,0 @@ -// Package codegen generates Go code from parsed OpenAPI specs. -package codegen - -import ( - "fmt" - "maps" - "slices" - "strings" - "text/template" - - "github.com/pb33f/libopenapi" - "github.com/pb33f/libopenapi/datamodel/high/base" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// Generate produces Go code from the parsed OpenAPI document. -// specData is the raw spec bytes used to embed the spec in the generated code. -func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (string, error) { - cfg.ApplyDefaults() - - // Create content type matcher for filtering request/response bodies - contentTypeMatcher := NewContentTypeMatcher(cfg.ContentTypes) - - // Create content type short namer for friendly type names - contentTypeNamer := NewContentTypeShortNamer(cfg.ContentTypeShortNames) - - // Pass 1: Gather all schemas that need types - schemas, err := GatherSchemas(doc, contentTypeMatcher) - if err != nil { - return "", fmt.Errorf("gathering schemas: %w", err) - } - - // Pass 2: Compute names for all schemas - converter := NewNameConverter(cfg.NameMangling, cfg.NameSubstitutions) - ComputeSchemaNames(schemas, converter, contentTypeNamer) - - // Build schema index for type resolution - schemaIndex := make(map[string]*SchemaDescriptor) - for _, s := range schemas { - schemaIndex[s.Path.String()] = s - } - - // Pass 3: Generate Go code - importResolver := NewImportResolver(cfg.ImportMapping) - tagGenerator := NewStructTagGenerator(cfg.StructTags) - gen := NewTypeGenerator(cfg.TypeMapping, converter, importResolver, tagGenerator) - gen.IndexSchemas(schemas) - - output := NewOutput(cfg.PackageName) - // Note: encoding/json and fmt imports are added by generateType when needed - - // Generate models (types for schemas) unless using external models package - if cfg.Generation.ModelsPackage == nil { - for _, desc := range schemas { - code := generateType(gen, desc) - if code != "" { - output.AddType(code) - } - } - - // Add imports collected during generation - output.AddImports(gen.Imports()) - - // Add custom type templates (Date, Email, UUID, File, etc.) - // Sort template names for deterministic output ordering. - templateNames := slices.Sorted(maps.Keys(gen.RequiredTemplates())) - for _, templateName := range templateNames { - typeCode, typeImports := loadCustomType(templateName) - if typeCode != "" { - output.AddType(typeCode) - for path, alias := range typeImports { - output.AddImport(path, alias) - } - } - } - - // Embed the raw OpenAPI spec if specData was provided - if len(specData) > 0 { - embeddedCode, err := generateEmbeddedSpec(specData) - if err != nil { - return "", fmt.Errorf("generating embedded spec: %w", err) - } - output.AddType(embeddedCode) - output.AddImport("bytes", "") - output.AddImport("compress/gzip", "") - output.AddImport("encoding/base64", "") - output.AddImport("fmt", "") - output.AddImport("strings", "") - output.AddImport("sync", "") - } - } - - // Generate client code if requested - if cfg.Generation.Client { - // Create param tracker for tracking which param functions are needed - paramTracker := NewParamUsageTracker() - - // Gather operations - ops, err := GatherOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering operations: %w", err) - } - - // Generate client - clientGen, err := NewClientGenerator(schemaIndex, cfg.Generation.SimpleClient, cfg.Generation.ModelsPackage) - if err != nil { - return "", fmt.Errorf("creating client generator: %w", err) - } - - clientCode, err := clientGen.GenerateClient(ops) - if err != nil { - return "", fmt.Errorf("generating client code: %w", err) - } - output.AddType(clientCode) - - // Add client imports - for _, ct := range templates.ClientTemplates { - for _, imp := range ct.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - // Add models package import if using external models - if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { - output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) - } - - // Generate param functions - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - - // Add param function imports - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - - // Track whether shared error types have been generated to avoid duplication. - // Both server and receiver generation emit the same error types. - generatedErrors := false - - // Generate server code for path operations if a server framework is set. - // Only generate if there are actual path operations — setting server solely - // for receiver use should not produce path-operation server code. - if cfg.Generation.Server != "" { - // Create param tracker for tracking which param functions are needed - paramTracker := NewParamUsageTracker() - - // Gather operations - ops, err := GatherOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering operations: %w", err) - } - - if len(ops) > 0 { - // Generate server - serverGen, err := NewServerGenerator(cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("creating server generator: %w", err) - } - - serverCode, err := serverGen.GenerateServer(ops) - if err != nil { - return "", fmt.Errorf("generating server code: %w", err) - } - output.AddType(serverCode) - generatedErrors = true - - // Add server imports based on server type - serverTemplates, err := getServerTemplates(cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("getting server templates: %w", err) - } - for _, st := range serverTemplates { - for _, imp := range st.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - // Note: Server interfaces don't use external models directly. - // Models are used in the hand-written implementation (petstore.go), - // not in the generated server interface code. - - // Generate param functions - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - - // Add param function imports - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - } - - // Generate webhook initiator code if requested - if cfg.Generation.WebhookInitiator { - paramTracker := NewParamUsageTracker() - - webhookOps, err := GatherWebhookOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering webhook operations: %w", err) - } - - if len(webhookOps) > 0 { - initiatorGen, err := NewInitiatorGenerator("Webhook", schemaIndex, true, cfg.Generation.ModelsPackage) - if err != nil { - return "", fmt.Errorf("creating webhook initiator generator: %w", err) - } - - initiatorCode, err := initiatorGen.GenerateInitiator(webhookOps) - if err != nil { - return "", fmt.Errorf("generating webhook initiator code: %w", err) - } - output.AddType(initiatorCode) - - for _, pt := range templates.InitiatorTemplates { - for _, imp := range pt.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { - output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) - } - - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - } - - // Generate callback initiator code if requested - if cfg.Generation.CallbackInitiator { - paramTracker := NewParamUsageTracker() - - callbackOps, err := GatherCallbackOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering callback operations: %w", err) - } - - if len(callbackOps) > 0 { - initiatorGen, err := NewInitiatorGenerator("Callback", schemaIndex, true, cfg.Generation.ModelsPackage) - if err != nil { - return "", fmt.Errorf("creating callback initiator generator: %w", err) - } - - initiatorCode, err := initiatorGen.GenerateInitiator(callbackOps) - if err != nil { - return "", fmt.Errorf("generating callback initiator code: %w", err) - } - output.AddType(initiatorCode) - - for _, pt := range templates.InitiatorTemplates { - for _, imp := range pt.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - if cfg.Generation.ModelsPackage != nil && cfg.Generation.ModelsPackage.Path != "" { - output.AddImport(cfg.Generation.ModelsPackage.Path, cfg.Generation.ModelsPackage.Alias) - } - - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - } - - // Generate webhook receiver code if requested - if cfg.Generation.WebhookReceiver { - if cfg.Generation.Server == "" { - return "", fmt.Errorf("webhook-receiver requires server to be set") - } - - paramTracker := NewParamUsageTracker() - - webhookOps, err := GatherWebhookOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering webhook operations: %w", err) - } - - if len(webhookOps) > 0 { - receiverGen, err := NewReceiverGenerator("Webhook", cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("creating webhook receiver generator: %w", err) - } - - receiverCode, err := receiverGen.GenerateReceiver(webhookOps) - if err != nil { - return "", fmt.Errorf("generating webhook receiver code: %w", err) - } - output.AddType(receiverCode) - - // Add param types - paramTypes, err := receiverGen.GenerateParamTypes(webhookOps) - if err != nil { - return "", fmt.Errorf("generating webhook receiver param types: %w", err) - } - output.AddType(paramTypes) - - // Add error types (only if not already generated by server) - if !generatedErrors { - errors, err := receiverGen.GenerateErrors() - if err != nil { - return "", fmt.Errorf("generating webhook receiver errors: %w", err) - } - output.AddType(errors) - generatedErrors = true - } - - receiverTemplates, err := getReceiverTemplates(cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("getting receiver templates: %w", err) - } - for _, ct := range receiverTemplates { - for _, imp := range ct.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - for _, st := range templates.SharedServerTemplates { - for _, imp := range st.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - } - - // Generate callback receiver code if requested - if cfg.Generation.CallbackReceiver { - if cfg.Generation.Server == "" { - return "", fmt.Errorf("callback-receiver requires server to be set") - } - - paramTracker := NewParamUsageTracker() - - callbackOps, err := GatherCallbackOperations(doc, paramTracker) - if err != nil { - return "", fmt.Errorf("gathering callback operations: %w", err) - } - - if len(callbackOps) > 0 { - receiverGen, err := NewReceiverGenerator("Callback", cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("creating callback receiver generator: %w", err) - } - - receiverCode, err := receiverGen.GenerateReceiver(callbackOps) - if err != nil { - return "", fmt.Errorf("generating callback receiver code: %w", err) - } - output.AddType(receiverCode) - - paramTypes, err := receiverGen.GenerateParamTypes(callbackOps) - if err != nil { - return "", fmt.Errorf("generating callback receiver param types: %w", err) - } - output.AddType(paramTypes) - - // Add error types (only if not already generated by server or another receiver) - if !generatedErrors { - errors, err := receiverGen.GenerateErrors() - if err != nil { - return "", fmt.Errorf("generating callback receiver errors: %w", err) - } - output.AddType(errors) - generatedErrors = true //nolint:ineffassign // kept for symmetry with webhook loop below - } - - receiverTemplates, err := getReceiverTemplates(cfg.Generation.Server) - if err != nil { - return "", fmt.Errorf("getting receiver templates: %w", err) - } - for _, ct := range receiverTemplates { - for _, imp := range ct.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - for _, st := range templates.SharedServerTemplates { - for _, imp := range st.Imports { - output.AddImport(imp.Path, imp.Alias) - } - } - - paramFuncs, err := generateParamFunctionsFromTracker(paramTracker) - if err != nil { - return "", fmt.Errorf("generating param functions: %w", err) - } - if paramFuncs != "" { - output.AddType(paramFuncs) - } - for _, imp := range paramTracker.GetRequiredImports() { - output.AddImport(imp.Path, imp.Alias) - } - } - } - - return output.Format() -} - -// generateParamFunctionsFromTracker generates the parameter styling/binding functions based on usage. -func generateParamFunctionsFromTracker(tracker *ParamUsageTracker) (string, error) { - if !tracker.HasAnyUsage() { - return "", nil - } - - var result strings.Builder - - // Get required templates - requiredTemplates := tracker.GetRequiredTemplates() - - for _, tmplInfo := range requiredTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + tmplInfo.Template) - if err != nil { - return "", fmt.Errorf("reading param template %s: %w", tmplInfo.Template, err) - } - - // Parse and execute as a Go template - tmpl, err := template.New(tmplInfo.Name).Parse(string(content)) - if err != nil { - return "", fmt.Errorf("parsing param template %s: %w", tmplInfo.Template, err) - } - - if err := tmpl.Execute(&result, nil); err != nil { - return "", fmt.Errorf("executing param template %s: %w", tmplInfo.Template, err) - } - result.WriteString("\n") - } - - return result.String(), nil -} - -// generateType generates Go code for a single schema descriptor. -func generateType(gen *TypeGenerator, desc *SchemaDescriptor) string { - kind := GetSchemaKind(desc) - - // If schema has TypeOverride extension, generate a type alias to the external type - // instead of generating the full type definition - if desc.Extensions != nil && desc.Extensions.TypeOverride != nil { - return generateTypeOverrideAlias(gen, desc) - } - - var code string - switch kind { - case KindReference: - // References don't generate new types; they use the referenced type's name - return "" - - case KindStruct: - code = generateStructType(gen, desc) - - case KindMap: - code = generateMapAlias(gen, desc) - - case KindEnum: - code = generateEnumType(gen, desc) - - case KindAllOf: - code = generateAllOfType(gen, desc) - - case KindAnyOf: - code = generateAnyOfType(gen, desc) - - case KindOneOf: - code = generateOneOfType(gen, desc) - - case KindAlias: - code = generateTypeAlias(gen, desc) - - default: - return "" - } - - if code == "" { - return "" - } - - // Prepend schema path comment - return schemaPathComment(desc.Path) + code -} - -// schemaPathComment returns a comment line showing the schema path. -func schemaPathComment(path SchemaPath) string { - return fmt.Sprintf("// %s\n", path.String()) -} - -// generateStructType generates a struct type for an object schema. -func generateStructType(gen *TypeGenerator, desc *SchemaDescriptor) string { - fields := gen.GenerateStructFields(desc) - doc := extractDescription(desc.Schema) - - // Check if we need additionalProperties handling - if gen.HasAdditionalProperties(desc) { - // Mixed properties need encoding/json for marshal/unmarshal (but not fmt) - gen.AddJSONImport() - - addPropsType := gen.AdditionalPropertiesType(desc) - structCode := GenerateStructWithAdditionalProps(desc.ShortName, fields, addPropsType, doc, gen.TagGenerator()) - - // Generate marshal/unmarshal methods - marshalCode := GenerateMixedPropertiesMarshal(desc.ShortName, fields) - unmarshalCode := GenerateMixedPropertiesUnmarshal(desc.ShortName, fields, addPropsType) - - code := structCode + "\n" + marshalCode + "\n" + unmarshalCode - - // Generate ApplyDefaults method if needed - if applyDefaults := GenerateApplyDefaults(desc.ShortName, fields); applyDefaults != "" { - code += "\n" + applyDefaults - } - - return code - } - - code := GenerateStruct(desc.ShortName, fields, doc, gen.TagGenerator()) - - // Generate ApplyDefaults method if needed - if applyDefaults := GenerateApplyDefaults(desc.ShortName, fields); applyDefaults != "" { - code += "\n" + applyDefaults - } - - return code -} - -// generateMapAlias generates a type alias for a pure map schema. -func generateMapAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { - mapType := gen.GoTypeExpr(desc) - doc := extractDescription(desc.Schema) - return GenerateTypeAlias(desc.ShortName, mapType, doc) -} - -// generateEnumType generates an enum type with const values. -func generateEnumType(gen *TypeGenerator, desc *SchemaDescriptor) string { - schema := desc.Schema - if schema == nil { - return "" - } - - // Determine base type - baseType := "string" - primaryType := getPrimaryType(schema) - if primaryType == "integer" { - baseType = "int" - } - - // Extract enum values as strings - var values []string - for _, v := range schema.Enum { - values = append(values, fmt.Sprintf("%v", v.Value)) - } - - // Check for custom enum variable names from extensions - var customNames []string - if desc.Extensions != nil && len(desc.Extensions.EnumVarNames) > 0 { - customNames = desc.Extensions.EnumVarNames - } - - doc := extractDescription(schema) - return GenerateEnumWithConstPrefix(desc.ShortName, desc.ShortName, baseType, values, customNames, doc) -} - -// generateTypeAlias generates a simple type alias. -func generateTypeAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { - goType := gen.GoTypeExpr(desc) - doc := extractDescription(desc.Schema) - return GenerateTypeAlias(desc.ShortName, goType, doc) -} - -// generateTypeOverrideAlias generates a type alias to an external type specified via x-oapi-codegen-type-override. -func generateTypeOverrideAlias(gen *TypeGenerator, desc *SchemaDescriptor) string { - override := desc.Extensions.TypeOverride - - // Register the import - if override.ImportPath != "" { - if override.ImportAlias != "" { - gen.AddImportAlias(override.ImportPath, override.ImportAlias) - } else { - gen.AddImport(override.ImportPath) - } - } - - doc := extractDescription(desc.Schema) - return GenerateTypeAlias(desc.ShortName, override.TypeName, doc) -} - -// AllOfMergeError represents a conflict when merging allOf schemas. -type AllOfMergeError struct { - SchemaName string - PropertyName string - Type1 string - Type2 string -} - -func (e AllOfMergeError) Error() string { - return fmt.Sprintf("allOf merge conflict in %s: property %q has conflicting types %s and %s", - e.SchemaName, e.PropertyName, e.Type1, e.Type2) -} - -// allOfMemberInfo holds information about an allOf member for merging. -type allOfMemberInfo struct { - fields []StructField // flattened fields from object schemas - unionType string // non-empty if this member is a oneOf/anyOf union - unionDesc *SchemaDescriptor - required []string // required fields from this allOf member -} - -// generateAllOfType generates a struct with flattened properties from all allOf members. -// Object schema properties are merged into flat fields. -// oneOf/anyOf members become union fields with json:"-" tag. -func generateAllOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { - schema := desc.Schema - if schema == nil { - return "" - } - - // Merge all fields, checking for conflicts - mergedFields := make(map[string]StructField) // keyed by JSONName - var fieldOrder []string // preserve order - var unionFields []StructField - - // First, collect fields from properties defined directly on the schema - // (Issue 2102: properties at same level as allOf were being ignored) - if schema.Properties != nil && schema.Properties.Len() > 0 { - directFields := gen.GenerateStructFields(desc) - for _, field := range directFields { - mergedFields[field.JSONName] = field - fieldOrder = append(fieldOrder, field.JSONName) - } - } - - // Collect info about each allOf member - var members []allOfMemberInfo - for i, proxy := range schema.AllOf { - info := allOfMemberInfo{} - - memberSchema := proxy.Schema() - if memberSchema == nil { - continue - } - - // Check if this member is a oneOf/anyOf (union type) - if len(memberSchema.OneOf) > 0 || len(memberSchema.AnyOf) > 0 { - // This is a union - keep as a union field - if desc.AllOf != nil && i < len(desc.AllOf) { - info.unionType = desc.AllOf[i].ShortName - info.unionDesc = desc.AllOf[i] - } - } else if proxy.IsReference() { - // Reference to another schema - get its fields - ref := proxy.GetReference() - if target, ok := gen.schemaIndex[ref]; ok { - info.fields = gen.collectFieldsRecursive(target) - } - } else if memberSchema.Properties != nil && memberSchema.Properties.Len() > 0 { - // Inline object schema - get its fields - if desc.AllOf != nil && i < len(desc.AllOf) { - info.fields = gen.GenerateStructFields(desc.AllOf[i]) - } - } - - // Also check for required array in allOf members (may mark fields as required) - info.required = memberSchema.Required - - members = append(members, info) - } - - // Merge fields from allOf members - for _, member := range members { - if member.unionType != "" { - // Add union as a special field - unionFields = append(unionFields, StructField{ - Name: member.unionType, - Type: "*" + member.unionType, - JSONName: "-", // will use json:"-" - }) - continue - } - - for _, field := range member.fields { - if existing, ok := mergedFields[field.JSONName]; ok { - // Check for type conflict - if existing.Type != field.Type { - // Type conflict - generate error comment in output - // In a real implementation, this should be a proper error - // For now, we'll include a comment and use the first type - field.Doc = fmt.Sprintf("CONFLICT: type %s vs %s", existing.Type, field.Type) - } - // If same type, keep existing (first wins for required/nullable) - continue - } - mergedFields[field.JSONName] = field - fieldOrder = append(fieldOrder, field.JSONName) - } - - // Apply required array from this allOf member to update pointer/omitempty - for _, reqName := range member.required { - if field, ok := mergedFields[reqName]; ok { - if !field.Required { - field.Required = true - field.OmitEmpty = false - // Update pointer status - required non-nullable fields are not pointers - if !field.Nullable && !strings.HasPrefix(field.Type, "[]") && !strings.HasPrefix(field.Type, "map[") { - field.Type = strings.TrimPrefix(field.Type, "*") - field.Pointer = false - } - mergedFields[reqName] = field - } - } - } - } - - // Build final field list in order - var finalFields []StructField - for _, jsonName := range fieldOrder { - finalFields = append(finalFields, mergedFields[jsonName]) - } - - doc := extractDescription(schema) - - // Generate struct - var code string - if len(unionFields) > 0 { - // Has union members - need custom marshal/unmarshal - gen.AddJSONImport() - code = generateAllOfStructWithUnions(desc.ShortName, finalFields, unionFields, doc, gen.TagGenerator()) - } else { - // Simple case - just flattened fields - code = GenerateStruct(desc.ShortName, finalFields, doc, gen.TagGenerator()) - } - - // Generate ApplyDefaults method if needed - if applyDefaults := GenerateApplyDefaults(desc.ShortName, finalFields); applyDefaults != "" { - code += "\n" + applyDefaults - } - - return code -} - -// generateAllOfStructWithUnions generates an allOf struct that contains union fields. -func generateAllOfStructWithUnions(name string, fields []StructField, unionFields []StructField, doc string, tagGen *StructTagGenerator) string { - b := NewCodeBuilder() - - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - b.Line("type %s struct {", name) - b.Indent() - - // Regular fields - for _, f := range fields { - tag := generateFieldTag(f, tagGen) - b.Line("%s %s %s", f.Name, f.Type, tag) - } - - // Union fields with json:"-" - for _, f := range unionFields { - b.Line("%s %s `json:\"-\"`", f.Name, f.Type) - } - - b.Dedent() - b.Line("}") - - // Generate MarshalJSON - b.BlankLine() - b.Line("func (s %s) MarshalJSON() ([]byte, error) {", name) - b.Indent() - b.Line("result := make(map[string]any)") - b.BlankLine() - - // Marshal regular fields - for _, f := range fields { - if f.Pointer { - b.Line("if s.%s != nil {", f.Name) - b.Indent() - b.Line("result[%q] = s.%s", f.JSONName, f.Name) - b.Dedent() - b.Line("}") - } else if strings.HasPrefix(f.Type, "[]") || strings.HasPrefix(f.Type, "map[") { - // Slices and maps - only include if not nil - b.Line("if s.%s != nil {", f.Name) - b.Indent() - b.Line("result[%q] = s.%s", f.JSONName, f.Name) - b.Dedent() - b.Line("}") - } else { - b.Line("result[%q] = s.%s", f.JSONName, f.Name) - } - } - - // Marshal and merge union fields - for _, f := range unionFields { - b.BlankLine() - b.Line("if s.%s != nil {", f.Name) - b.Indent() - b.Line("unionData, err := json.Marshal(s.%s)", f.Name) - b.Line("if err != nil {") - b.Indent() - b.Line("return nil, err") - b.Dedent() - b.Line("}") - b.Line("var unionMap map[string]any") - b.Line("if err := json.Unmarshal(unionData, &unionMap); err == nil {") - b.Indent() - b.Line("for k, v := range unionMap {") - b.Indent() - b.Line("result[k] = v") - b.Dedent() - b.Line("}") - b.Dedent() - b.Line("}") - b.Dedent() - b.Line("}") - } - - b.BlankLine() - b.Line("return json.Marshal(result)") - b.Dedent() - b.Line("}") - - // Generate UnmarshalJSON - b.BlankLine() - b.Line("func (s *%s) UnmarshalJSON(data []byte) error {", name) - b.Indent() - - // Unmarshal into raw map for field extraction - b.Line("var raw map[string]json.RawMessage") - b.Line("if err := json.Unmarshal(data, &raw); err != nil {") - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.BlankLine() - - // Unmarshal known fields - for _, f := range fields { - b.Line("if v, ok := raw[%q]; ok {", f.JSONName) - b.Indent() - if f.Pointer { - baseType := strings.TrimPrefix(f.Type, "*") - b.Line("var val %s", baseType) - b.Line("if err := json.Unmarshal(v, &val); err != nil {") - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.Line("s.%s = &val", f.Name) - } else { - b.Line("if err := json.Unmarshal(v, &s.%s); err != nil {", f.Name) - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - } - b.Dedent() - b.Line("}") - } - - // Unmarshal union fields from the full data - for _, f := range unionFields { - b.BlankLine() - baseType := strings.TrimPrefix(f.Type, "*") - b.Line("var %sVal %s", f.Name, baseType) - b.Line("if err := json.Unmarshal(data, &%sVal); err != nil {", f.Name) - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.Line("s.%s = &%sVal", f.Name, f.Name) - } - - b.BlankLine() - b.Line("return nil") - b.Dedent() - b.Line("}") - - return b.String() -} - -// generateAnyOfType generates a union type for anyOf schemas. -func generateAnyOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { - members := collectUnionMembers(gen, desc, desc.AnyOf, desc.Schema.AnyOf) - if len(members) == 0 { - return "" - } - - // anyOf types only need encoding/json (not fmt like oneOf) - gen.AddJSONImport() - - doc := extractDescription(desc.Schema) - code := GenerateUnionType(desc.ShortName, members, false, doc) - - marshalCode := GenerateUnionMarshalAnyOf(desc.ShortName, members) - unmarshalCode := GenerateUnionUnmarshalAnyOf(desc.ShortName, members) - applyDefaultsCode := GenerateUnionApplyDefaults(desc.ShortName, members) - - code += "\n" + marshalCode + "\n" + unmarshalCode + "\n" + applyDefaultsCode - - return code -} - -// generateOneOfType generates a union type for oneOf schemas. -func generateOneOfType(gen *TypeGenerator, desc *SchemaDescriptor) string { - members := collectUnionMembers(gen, desc, desc.OneOf, desc.Schema.OneOf) - if len(members) == 0 { - return "" - } - - // Union types need encoding/json and fmt for marshal/unmarshal - gen.AddJSONImports() - - doc := extractDescription(desc.Schema) - code := GenerateUnionType(desc.ShortName, members, true, doc) - - marshalCode := GenerateUnionMarshalOneOf(desc.ShortName, members) - unmarshalCode := GenerateUnionUnmarshalOneOf(desc.ShortName, members) - applyDefaultsCode := GenerateUnionApplyDefaults(desc.ShortName, members) - - code += "\n" + marshalCode + "\n" + unmarshalCode + "\n" + applyDefaultsCode - - return code -} - -// loadCustomType loads a custom type template and returns its code and imports. -func loadCustomType(templateName string) (string, map[string]string) { - // Lookup the type definition - typeName := strings.TrimSuffix(templateName, ".tmpl") - - // Map template name to type info from registry - var typeDef templates.TypeTemplate - var found bool - - for name, def := range templates.TypeTemplates { - if def.Template == "types/"+templateName || strings.ToLower(name) == typeName { - typeDef = def - found = true - break - } - } - - if !found { - return "", nil - } - - // Read the template file - content, err := templates.TemplateFS.ReadFile("files/" + typeDef.Template) - if err != nil { - return "", nil - } - - // Remove the template comment header - code := string(content) - if idx := strings.Index(code, "}}"); idx != -1 { - code = strings.TrimLeft(code[idx+2:], "\n") - } - - // Build imports map - imports := make(map[string]string) - for _, imp := range typeDef.Imports { - imports[imp.Path] = imp.Alias - } - - return code, imports -} - -// schemaHasApplyDefaults returns true if the schema will have an ApplyDefaults method generated. -// This is true for: -// - Object types with properties -// - Union types (oneOf/anyOf) -// - AllOf types (merged structs) -// This is false for: -// - Primitive types (string, integer, boolean, number) -// - Enum types (without object properties) -// - Arrays -// - Maps (additionalProperties only) -func schemaHasApplyDefaults(schema *base.Schema) bool { - if schema == nil { - return false - } - - // Has properties -> object type with ApplyDefaults - if schema.Properties != nil && schema.Properties.Len() > 0 { - return true - } - - // Has oneOf/anyOf -> union type with ApplyDefaults - if len(schema.OneOf) > 0 || len(schema.AnyOf) > 0 { - return true - } - - // Has allOf -> merged struct with ApplyDefaults - if len(schema.AllOf) > 0 { - return true - } - - return false -} - -// collectUnionMembers gathers union member information for anyOf/oneOf. -func collectUnionMembers(gen *TypeGenerator, parentDesc *SchemaDescriptor, memberDescs []*SchemaDescriptor, memberProxies []*base.SchemaProxy) []UnionMember { - var members []UnionMember - - // Build a map of schema paths to descriptors for lookup - descByPath := make(map[string]*SchemaDescriptor) - for _, desc := range memberDescs { - if desc != nil { - descByPath[desc.Path.String()] = desc - } - } - - for i, proxy := range memberProxies { - var memberType string - var fieldName string - var hasApplyDefaults bool - - if proxy.IsReference() { - ref := proxy.GetReference() - if target, ok := gen.schemaIndex[ref]; ok { - memberType = target.ShortName - fieldName = target.ShortName - hasApplyDefaults = schemaHasApplyDefaults(target.Schema) - } else { - continue - } - } else { - // Check if this inline schema has a descriptor - schema := proxy.Schema() - if schema == nil { - continue - } - - // Determine the path for this member to look up its descriptor - var memberPath SchemaPath - if parentDesc != nil { - // Try to find a descriptor by constructing the expected path - memberPath = parentDesc.Path.Append("anyOf", fmt.Sprintf("%d", i)) - if _, ok := descByPath[memberPath.String()]; !ok { - memberPath = parentDesc.Path.Append("oneOf", fmt.Sprintf("%d", i)) - } - } - - if desc, ok := descByPath[memberPath.String()]; ok && desc.ShortName != "" { - memberType = desc.ShortName - fieldName = desc.ShortName - hasApplyDefaults = schemaHasApplyDefaults(desc.Schema) - } else { - // This is a primitive type that doesn't have a named type - goType := gen.goTypeForSchema(schema, nil) - memberType = goType - // Create a field name based on the type - fieldName = gen.converter.ToTypeName(goType) + fmt.Sprintf("%d", i) - hasApplyDefaults = false // Primitive types don't have ApplyDefaults - } - } - - members = append(members, UnionMember{ - FieldName: fieldName, - TypeName: memberType, - Index: i, - HasApplyDefaults: hasApplyDefaults, - }) - } - - return members -} diff --git a/experimental/internal/codegen/configuration.go b/experimental/internal/codegen/configuration.go deleted file mode 100644 index c8d1b87388..0000000000 --- a/experimental/internal/codegen/configuration.go +++ /dev/null @@ -1,317 +0,0 @@ -package codegen - -import ( - "crypto/sha256" - "encoding/hex" - "regexp" - "sort" - "strings" -) - -type Configuration struct { - // PackageName which will be used in all generated files - PackageName string `yaml:"package"` - // Output specifies the output file path - Output string `yaml:"output"` - // Generation controls which parts of the code are generated - Generation GenerationOptions `yaml:"generation,omitempty"` - // TypeMapping allows customizing OpenAPI type/format to Go type mappings - TypeMapping TypeMapping `yaml:"type-mapping,omitempty"` - // NameMangling configures how OpenAPI names are converted to Go identifiers - NameMangling NameMangling `yaml:"name-mangling,omitempty"` - // NameSubstitutions allows direct overrides of generated names - NameSubstitutions NameSubstitutions `yaml:"name-substitutions,omitempty"` - // ImportMapping maps external spec file paths to Go package import paths. - // Example: {"../common/api.yaml": "github.com/org/project/common"} - // Use "-" as the value to indicate types should be in the current package. - ImportMapping map[string]string `yaml:"import-mapping,omitempty"` - // ContentTypes is a list of regexp patterns for media types to generate models for. - // Only request/response bodies with matching content types will have types generated. - // Defaults to common JSON and YAML types if not specified. - ContentTypes []string `yaml:"content-types,omitempty"` - // ContentTypeShortNames maps content type regex patterns to short names for use in type names. - // Example: {"^application/json$": "JSON", "^application/xml$": "XML"} - // These are used when generating response/request type names like "FindPetsJSONResponse". - ContentTypeShortNames []ContentTypeShortName `yaml:"content-type-short-names,omitempty"` - // StructTags configures how struct tags are generated for fields. - // By default, only json tags are generated. - StructTags StructTagsConfig `yaml:"struct-tags,omitempty"` -} - -// ModelsPackage specifies an external package containing the model types. -type ModelsPackage struct { - // Path is the import path for the models package (e.g., "github.com/org/project/models") - Path string `yaml:"path"` - // Alias is an optional import alias. If empty, the last segment of the path is used. - Alias string `yaml:"alias,omitempty"` -} - -// Name returns the package name/alias to use for qualifying types. -// Returns the Alias if set, otherwise derives from the Path. -func (m *ModelsPackage) Name() string { - if m == nil || m.Path == "" { - return "" - } - if m.Alias != "" { - return m.Alias - } - // Derive from path - take last segment - parts := strings.Split(m.Path, "/") - return parts[len(parts)-1] -} - -// Prefix returns the package prefix for qualifying types (e.g., "models."). -// Returns empty string if models are in the same package. -func (m *ModelsPackage) Prefix() string { - name := m.Name() - if name == "" { - return "" - } - return name + "." -} - -// ContentTypeShortName maps a content type pattern to a short name. -type ContentTypeShortName struct { - // Pattern is a regex pattern to match against content types - Pattern string `yaml:"pattern"` - // ShortName is the short name to use in generated type names (e.g., "JSON", "XML") - ShortName string `yaml:"short-name"` -} - -// GenerationOptions controls which parts of the code are generated. -type GenerationOptions struct { - // Server specifies which server framework to generate code for. - // Supported values: "std-http" - // Empty string (default) means no server code is generated. - Server string `yaml:"server,omitempty"` - - // Client enables generation of the HTTP client. - // When true, generates a base Client that returns *http.Response. - Client bool `yaml:"client,omitempty"` - - // SimpleClient enables generation of the SimpleClient wrapper. - // SimpleClient wraps the base Client with typed responses for - // operations that have unambiguous response types. - // Requires Client to also be enabled. - SimpleClient bool `yaml:"simple-client,omitempty"` - - // WebhookInitiator enables generation of webhook initiator code (sends webhook requests). - // Generates a framework-agnostic client that takes the full target URL per-call. - WebhookInitiator bool `yaml:"webhook-initiator,omitempty"` - - // WebhookReceiver enables generation of webhook receiver code (receives webhook requests). - // Generates framework-specific handler functions. Requires Server to be set. - WebhookReceiver bool `yaml:"webhook-receiver,omitempty"` - - // CallbackInitiator enables generation of callback initiator code (sends callback requests). - // Generates a framework-agnostic client that takes the full target URL per-call. - CallbackInitiator bool `yaml:"callback-initiator,omitempty"` - - // CallbackReceiver enables generation of callback receiver code (receives callback requests). - // Generates framework-specific handler functions. Requires Server to be set. - CallbackReceiver bool `yaml:"callback-receiver,omitempty"` - - // ModelsPackage specifies an external package containing the model types. - // When set, models are NOT generated locally - instead, generated code - // imports and references types from this package. - // Example: {path: "github.com/org/project/models"} - ModelsPackage *ModelsPackage `yaml:"models-package,omitempty"` -} - -// ServerType constants for supported server frameworks. -const ( - ServerTypeStdHTTP = "std-http" - ServerTypeChi = "chi" - ServerTypeEcho = "echo" - ServerTypeEchoV4 = "echo/v4" - ServerTypeGin = "gin" - ServerTypeGorilla = "gorilla" - ServerTypeFiber = "fiber" - ServerTypeIris = "iris" -) - -// DefaultContentTypes returns the default list of content type patterns. -// These match common JSON and YAML media types. -func DefaultContentTypes() []string { - return []string{ - `^application/json$`, - `^application/.*\+json$`, - } -} - -// DefaultContentTypeShortNames returns the default content type to short name mappings. -func DefaultContentTypeShortNames() []ContentTypeShortName { - return []ContentTypeShortName{ - {Pattern: `^application/json$`, ShortName: "JSON"}, - {Pattern: `^application/.*\+json$`, ShortName: "JSON"}, - {Pattern: `^application/xml$`, ShortName: "XML"}, - {Pattern: `^application/.*\+xml$`, ShortName: "XML"}, - {Pattern: `^text/xml$`, ShortName: "XML"}, - {Pattern: `^text/plain$`, ShortName: "Text"}, - {Pattern: `^text/html$`, ShortName: "HTML"}, - {Pattern: `^application/octet-stream$`, ShortName: "Binary"}, - {Pattern: `^multipart/form-data$`, ShortName: "Multipart"}, - {Pattern: `^application/x-www-form-urlencoded$`, ShortName: "Form"}, - } -} - -// ApplyDefaults merges user configuration on top of default values. -func (c *Configuration) ApplyDefaults() { - c.TypeMapping = DefaultTypeMapping.Merge(c.TypeMapping) - c.NameMangling = DefaultNameMangling().Merge(c.NameMangling) - if len(c.ContentTypes) == 0 { - c.ContentTypes = DefaultContentTypes() - } - if len(c.ContentTypeShortNames) == 0 { - c.ContentTypeShortNames = DefaultContentTypeShortNames() - } - c.StructTags = DefaultStructTagsConfig().Merge(c.StructTags) -} - -// ContentTypeMatcher checks if content types match configured patterns. -type ContentTypeMatcher struct { - patterns []*regexp.Regexp -} - -// NewContentTypeMatcher creates a matcher from a list of regexp patterns. -// Invalid patterns are silently ignored. -func NewContentTypeMatcher(patterns []string) *ContentTypeMatcher { - m := &ContentTypeMatcher{ - patterns: make([]*regexp.Regexp, 0, len(patterns)), - } - for _, p := range patterns { - if re, err := regexp.Compile(p); err == nil { - m.patterns = append(m.patterns, re) - } - } - return m -} - -// Matches returns true if the content type matches any of the configured patterns. -func (m *ContentTypeMatcher) Matches(contentType string) bool { - for _, re := range m.patterns { - if re.MatchString(contentType) { - return true - } - } - return false -} - -// ContentTypeShortNamer resolves content types to short names for use in type names. -type ContentTypeShortNamer struct { - patterns []*regexp.Regexp - shortNames []string -} - -// NewContentTypeShortNamer creates a short namer from configuration. -func NewContentTypeShortNamer(mappings []ContentTypeShortName) *ContentTypeShortNamer { - n := &ContentTypeShortNamer{ - patterns: make([]*regexp.Regexp, 0, len(mappings)), - shortNames: make([]string, 0, len(mappings)), - } - for _, m := range mappings { - if re, err := regexp.Compile(m.Pattern); err == nil { - n.patterns = append(n.patterns, re) - n.shortNames = append(n.shortNames, m.ShortName) - } - } - return n -} - -// ShortName returns the short name for a content type, or a fallback derived from the content type. -func (n *ContentTypeShortNamer) ShortName(contentType string) string { - for i, re := range n.patterns { - if re.MatchString(contentType) { - return n.shortNames[i] - } - } - // Fallback: derive from content type (e.g., "application/vnd.api+json" -> "VndApiJson") - return deriveContentTypeShortName(contentType) -} - -// deriveContentTypeShortName creates a short name from an unmatched content type. -func deriveContentTypeShortName(contentType string) string { - // Remove "application/", "text/", etc. prefix - if idx := strings.Index(contentType, "/"); idx >= 0 { - contentType = contentType[idx+1:] - } - // Replace non-alphanumeric with spaces for word splitting - var result strings.Builder - capitalizeNext := true - for _, r := range contentType { - if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' { - if capitalizeNext { - if r >= 'a' && r <= 'z' { - r = r - 'a' + 'A' - } - capitalizeNext = false - } - result.WriteRune(r) - } else { - capitalizeNext = true - } - } - return result.String() -} - -// ExternalImport represents an external package import with its alias. -type ExternalImport struct { - Alias string // Short alias for use in generated code (e.g., "ext_a1b2c3") - Path string // Full import path (e.g., "github.com/org/project/common") -} - -// ImportResolver resolves external references to Go package imports. -type ImportResolver struct { - mapping map[string]ExternalImport // spec file path -> import info -} - -// NewImportResolver creates an ImportResolver from the configuration's import mapping. -func NewImportResolver(importMapping map[string]string) *ImportResolver { - resolver := &ImportResolver{ - mapping: make(map[string]ExternalImport), - } - - for specPath, pkgPath := range importMapping { - if pkgPath == "-" { - // "-" means current package, no import needed - resolver.mapping[specPath] = ExternalImport{Alias: "", Path: ""} - } else { - resolver.mapping[specPath] = ExternalImport{ - Alias: hashImportAlias(pkgPath), - Path: pkgPath, - } - } - } - - return resolver -} - -// Resolve looks up an external spec file path and returns its import info. -// Returns nil if the path is not in the mapping. -func (r *ImportResolver) Resolve(specPath string) *ExternalImport { - if imp, ok := r.mapping[specPath]; ok { - return &imp - } - return nil -} - -// AllImports returns all external imports sorted by alias. -func (r *ImportResolver) AllImports() []ExternalImport { - var imports []ExternalImport - for _, imp := range r.mapping { - if imp.Path != "" { // Skip current package markers - imports = append(imports, imp) - } - } - sort.Slice(imports, func(i, j int) bool { - return imports[i].Alias < imports[j].Alias - }) - return imports -} - -// hashImportAlias generates a short, deterministic alias from an import path. -// Uses first 8 characters of SHA256 hash prefixed with "ext_". -func hashImportAlias(importPath string) string { - h := sha256.Sum256([]byte(importPath)) - return "ext_" + hex.EncodeToString(h[:])[:8] -} diff --git a/experimental/internal/codegen/configuration_test.go b/experimental/internal/codegen/configuration_test.go deleted file mode 100644 index 700c65505a..0000000000 --- a/experimental/internal/codegen/configuration_test.go +++ /dev/null @@ -1,152 +0,0 @@ -package codegen - -import ( - "testing" - - "gopkg.in/yaml.v3" -) - -func TestContentTypeMatcher(t *testing.T) { - tests := []struct { - name string - patterns []string - contentType string - want bool - }{ - // Default patterns - JSON only (YAML not supported without custom unmarshalers) - {"json exact", DefaultContentTypes(), "application/json", true}, - {"json+suffix", DefaultContentTypes(), "application/vnd.api+json", true}, - {"problem+json", DefaultContentTypes(), "application/problem+json", true}, - - // YAML not in defaults (would need custom unmarshalers) - {"yaml not default", DefaultContentTypes(), "application/yaml", false}, - {"text/yaml not default", DefaultContentTypes(), "text/yaml", false}, - - // Non-matching - {"text/plain", DefaultContentTypes(), "text/plain", false}, - {"text/html", DefaultContentTypes(), "text/html", false}, - {"application/xml", DefaultContentTypes(), "application/xml", false}, - {"application/octet-stream", DefaultContentTypes(), "application/octet-stream", false}, - {"multipart/form-data", DefaultContentTypes(), "multipart/form-data", false}, - {"image/png", DefaultContentTypes(), "image/png", false}, - - // Custom patterns - {"custom xml", []string{`^application/xml$`}, "application/xml", true}, - {"custom xml no match", []string{`^application/xml$`}, "application/json", false}, - {"custom wildcard", []string{`^text/.*`}, "text/plain", true}, - {"custom wildcard html", []string{`^text/.*`}, "text/html", true}, - {"custom yaml", []string{`^application/yaml$`}, "application/yaml", true}, - - // Empty patterns - {"empty patterns", []string{}, "application/json", false}, - - // Invalid pattern (silently ignored) - {"invalid pattern", []string{`[invalid`}, "application/json", false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := NewContentTypeMatcher(tt.patterns) - got := m.Matches(tt.contentType) - if got != tt.want { - t.Errorf("Matches(%q) = %v, want %v", tt.contentType, got, tt.want) - } - }) - } -} - -func TestDefaultContentTypes(t *testing.T) { - defaults := DefaultContentTypes() - if len(defaults) == 0 { - t.Error("DefaultContentTypes() returned empty slice") - } - - // Verify all patterns are valid regexps - m := NewContentTypeMatcher(defaults) - if len(m.patterns) != len(defaults) { - t.Errorf("Some default patterns failed to compile: got %d patterns, want %d", - len(m.patterns), len(defaults)) - } -} - -func TestGenerationOptions_ServerYAML(t *testing.T) { - t.Run("unmarshal server field", func(t *testing.T) { - yamlContent := ` -generation: - server: std-http -` - var cfg Configuration - err := yaml.Unmarshal([]byte(yamlContent), &cfg) - if err != nil { - t.Fatalf("yaml.Unmarshal failed: %v", err) - } - if cfg.Generation.Server != ServerTypeStdHTTP { - t.Errorf("Server = %q, want %q", cfg.Generation.Server, ServerTypeStdHTTP) - } - }) - - t.Run("unmarshal empty server field", func(t *testing.T) { - yamlContent := ` -generation: - no-models: true -` - var cfg Configuration - err := yaml.Unmarshal([]byte(yamlContent), &cfg) - if err != nil { - t.Fatalf("yaml.Unmarshal failed: %v", err) - } - if cfg.Generation.Server != "" { - t.Errorf("Server = %q, want empty string", cfg.Generation.Server) - } - }) - - t.Run("marshal server field", func(t *testing.T) { - cfg := Configuration{ - PackageName: "test", - Generation: GenerationOptions{ - Server: ServerTypeStdHTTP, - }, - } - data, err := yaml.Marshal(&cfg) - if err != nil { - t.Fatalf("yaml.Marshal failed: %v", err) - } - if got := string(data); !contains(got, "server: std-http") { - t.Errorf("Marshaled YAML does not contain 'server: std-http':\n%s", got) - } - }) - - t.Run("omit empty server field", func(t *testing.T) { - cfg := Configuration{ - PackageName: "test", - Generation: GenerationOptions{}, - } - data, err := yaml.Marshal(&cfg) - if err != nil { - t.Fatalf("yaml.Marshal failed: %v", err) - } - if got := string(data); contains(got, "server:") { - t.Errorf("Marshaled YAML should not contain 'server:' when empty:\n%s", got) - } - }) -} - -func TestServerTypeConstants(t *testing.T) { - if ServerTypeStdHTTP != "std-http" { - t.Errorf("ServerTypeStdHTTP = %q, want %q", ServerTypeStdHTTP, "std-http") - } -} - -// contains is a simple helper for string containment check -func contains(s, substr string) bool { - return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsAt(s, substr)) -} - -func containsAt(s, substr string) bool { - for i := 0; i <= len(s)-len(substr); i++ { - if s[i:i+len(substr)] == substr { - return true - } - } - return false -} diff --git a/experimental/internal/codegen/extension.go b/experimental/internal/codegen/extension.go deleted file mode 100644 index f3f48dcbb3..0000000000 --- a/experimental/internal/codegen/extension.go +++ /dev/null @@ -1,337 +0,0 @@ -// Package codegen provides extension handling for OpenAPI x- properties. -package codegen - -import ( - "fmt" - "strings" - - "github.com/pb33f/libopenapi/orderedmap" - "go.yaml.in/yaml/v4" -) - -// Extension names - new naming convention with x-oapi-codegen- prefix -const ( - // ExtTypeOverride specifies an external type to use instead of generating one. - // Format: "TypeName" or "TypeName;import/path" or "TypeName;alias import/path" - ExtTypeOverride = "x-oapi-codegen-type-override" - - // ExtNameOverride overrides the generated field name. - ExtNameOverride = "x-oapi-codegen-name-override" - - // ExtTypeNameOverride overrides the generated type name. - ExtTypeNameOverride = "x-oapi-codegen-type-name-override" - - // ExtSkipOptionalPointer skips pointer wrapping for optional fields. - ExtSkipOptionalPointer = "x-oapi-codegen-skip-optional-pointer" - - // ExtJSONIgnore excludes the field from JSON marshaling (json:"-"). - ExtJSONIgnore = "x-oapi-codegen-json-ignore" - - // ExtOmitEmpty explicitly controls the omitempty JSON tag. - ExtOmitEmpty = "x-oapi-codegen-omitempty" - - // ExtOmitZero adds omitzero to the JSON tag (Go 1.24+ encoding/json/v2). - ExtOmitZero = "x-oapi-codegen-omitzero" - - // ExtEnumVarNames overrides the generated enum constant names. - ExtEnumVarNames = "x-oapi-codegen-enum-varnames" - - // ExtDeprecatedReason provides a deprecation reason for documentation. - ExtDeprecatedReason = "x-oapi-codegen-deprecated-reason" - - // ExtOrder controls field ordering in generated structs. - ExtOrder = "x-oapi-codegen-order" -) - -// Legacy extension names for backwards compatibility -const ( - legacyExtGoType = "x-go-type" - legacyExtGoTypeImport = "x-go-type-import" - legacyExtGoName = "x-go-name" - legacyExtGoTypeName = "x-go-type-name" - legacyExtGoTypeSkipOptionalPtr = "x-go-type-skip-optional-pointer" - legacyExtGoJSONIgnore = "x-go-json-ignore" - legacyExtOmitEmpty = "x-omitempty" - legacyExtOmitZero = "x-omitzero" - legacyExtEnumVarNames = "x-enum-varnames" - legacyExtEnumNames = "x-enumNames" // Alternative name - legacyExtDeprecatedReason = "x-deprecated-reason" - legacyExtOrder = "x-order" -) - -// TypeOverride represents an external type override with optional import. -type TypeOverride struct { - TypeName string // The Go type name (e.g., "uuid.UUID") - ImportPath string // Import path (e.g., "github.com/google/uuid") - ImportAlias string // Optional import alias (e.g., "foo" for `import foo "..."`) -} - -// Extensions holds parsed extension values for a schema or property. -type Extensions struct { - TypeOverride *TypeOverride // External type to use - NameOverride string // Override field name - TypeNameOverride string // Override generated type name - SkipOptionalPointer *bool // Skip pointer for optional fields - JSONIgnore *bool // Exclude from JSON - OmitEmpty *bool // Control omitempty - OmitZero *bool // Control omitzero - EnumVarNames []string // Override enum constant names - DeprecatedReason string // Deprecation reason - Order *int // Field ordering -} - -// ParseExtensions extracts extension values from a schema's extensions map. -// It supports both new (x-oapi-codegen-*) and legacy (x-go-*) extension names, -// logging deprecation warnings for legacy names. -func ParseExtensions(extensions *orderedmap.Map[string, *yaml.Node], path string) (*Extensions, error) { - if extensions == nil { - return &Extensions{}, nil - } - - ext := &Extensions{} - - // Legacy type override needs special handling: x-go-type and x-go-type-import - // are separate extensions that must be combined - var legacyGoType string - var legacyGoTypeImport any - - for pair := extensions.First(); pair != nil; pair = pair.Next() { - key := pair.Key() - node := pair.Value() - if node == nil { - continue - } - - val := decodeYAMLNode(node) - - switch key { - case ExtTypeOverride: - override, err := parseTypeOverride(val) - if err != nil { - return nil, fmt.Errorf("parsing %s: %w", key, err) - } - ext.TypeOverride = override - - case legacyExtGoType: - if s, ok := val.(string); ok { - legacyGoType = s - } - - case legacyExtGoTypeImport: - legacyGoTypeImport = val - - case ExtNameOverride, legacyExtGoName: - s, err := asString(val, key) - if err != nil { - return nil, err - } - ext.NameOverride = s - - case ExtTypeNameOverride, legacyExtGoTypeName: - s, err := asString(val, key) - if err != nil { - return nil, err - } - ext.TypeNameOverride = s - - case ExtSkipOptionalPointer, legacyExtGoTypeSkipOptionalPtr: - b, err := asBool(val, key) - if err != nil { - return nil, err - } - ext.SkipOptionalPointer = &b - - case ExtJSONIgnore, legacyExtGoJSONIgnore: - b, err := asBool(val, key) - if err != nil { - return nil, err - } - ext.JSONIgnore = &b - - case ExtOmitEmpty, legacyExtOmitEmpty: - b, err := asBool(val, key) - if err != nil { - return nil, err - } - ext.OmitEmpty = &b - - case ExtOmitZero, legacyExtOmitZero: - b, err := asBool(val, key) - if err != nil { - return nil, err - } - ext.OmitZero = &b - - case ExtEnumVarNames, legacyExtEnumVarNames, legacyExtEnumNames: - s, err := asStringSlice(val, key) - if err != nil { - return nil, err - } - ext.EnumVarNames = s - - case ExtDeprecatedReason, legacyExtDeprecatedReason: - s, err := asString(val, key) - if err != nil { - return nil, err - } - ext.DeprecatedReason = s - - case ExtOrder, legacyExtOrder: - i, err := asInt(val, key) - if err != nil { - return nil, err - } - ext.Order = &i - - default: - // Unknown extension - ignore - } - } - - // Combine legacy x-go-type and x-go-type-import if no new-style override was set - if ext.TypeOverride == nil && legacyGoType != "" { - ext.TypeOverride = buildLegacyTypeOverride(legacyGoType, legacyGoTypeImport) - } - - return ext, nil -} - -// hasExtension checks if an extension exists by either the new or legacy name. -// This is used to check for extensions before fully parsing them. -func hasExtension(extensions *orderedmap.Map[string, *yaml.Node], newName, legacyName string) bool { - if extensions == nil { - return false - } - - for pair := extensions.First(); pair != nil; pair = pair.Next() { - key := pair.Key() - if key == newName || key == legacyName { - return true - } - } - return false -} - -// decodeYAMLNode converts a yaml.Node to a Go value. -func decodeYAMLNode(node *yaml.Node) any { - if node == nil { - return nil - } - - var result any - if err := node.Decode(&result); err != nil { - return nil - } - return result -} - -// parseTypeOverride parses the new combined type override format. -// Format: "TypeName" or "TypeName;import/path" or "TypeName;alias import/path" -func parseTypeOverride(val any) (*TypeOverride, error) { - str, ok := val.(string) - if !ok { - return nil, fmt.Errorf("expected string, got %T", val) - } - - override := &TypeOverride{} - parts := strings.SplitN(str, ";", 2) - override.TypeName = strings.TrimSpace(parts[0]) - - if len(parts) == 2 { - importPart := strings.TrimSpace(parts[1]) - importParts := strings.SplitN(importPart, " ", 2) - if len(importParts) == 2 { - override.ImportAlias = strings.TrimSpace(importParts[0]) - override.ImportPath = strings.TrimSpace(importParts[1]) - } else { - override.ImportPath = importPart - } - } - - return override, nil -} - -// buildLegacyTypeOverride combines legacy x-go-type and x-go-type-import values. -func buildLegacyTypeOverride(typeName string, importVal any) *TypeOverride { - override := &TypeOverride{ - TypeName: typeName, - } - - if importVal == nil { - return override - } - - // Legacy import can be a string or an object with path/name - switch v := importVal.(type) { - case string: - override.ImportPath = v - case map[string]any: - if p, ok := v["path"].(string); ok { - override.ImportPath = p - } - if name, ok := v["name"].(string); ok { - override.ImportAlias = name - } - } - - return override -} - -// Type conversion helpers that include the extension name in error messages - -func asString(val any, extName string) (string, error) { - if val == nil { - return "", nil - } - str, ok := val.(string) - if !ok { - return "", fmt.Errorf("parsing %s: expected string, got %T", extName, val) - } - return str, nil -} - -func asBool(val any, extName string) (bool, error) { - if val == nil { - return false, nil - } - b, ok := val.(bool) - if !ok { - return false, fmt.Errorf("parsing %s: expected bool, got %T", extName, val) - } - return b, nil -} - -func asInt(val any, extName string) (int, error) { - if val == nil { - return 0, nil - } - switch v := val.(type) { - case int: - return v, nil - case int64: - return int(v), nil - case float64: - return int(v), nil - default: - return 0, fmt.Errorf("parsing %s: expected int, got %T", extName, val) - } -} - -func asStringSlice(val any, extName string) ([]string, error) { - if val == nil { - return nil, nil - } - slice, ok := val.([]any) - if !ok { - return nil, fmt.Errorf("parsing %s: expected array, got %T", extName, val) - } - result := make([]string, len(slice)) - for i, v := range slice { - str, ok := v.(string) - if !ok { - return nil, fmt.Errorf("parsing %s: expected string at index %d, got %T", extName, i, v) - } - result[i] = str - } - return result, nil -} diff --git a/experimental/internal/codegen/extension_integration_test.go b/experimental/internal/codegen/extension_integration_test.go deleted file mode 100644 index c100af7333..0000000000 --- a/experimental/internal/codegen/extension_integration_test.go +++ /dev/null @@ -1,201 +0,0 @@ -package codegen - -import ( - "strings" - "testing" - - "github.com/pb33f/libopenapi" -) - -func TestExtensionIntegration(t *testing.T) { - spec := ` -openapi: "3.1.0" -info: - title: Extension Test API - version: "1.0" -paths: {} -components: - schemas: - # Test type-name-override - MySchema: - type: object - x-oapi-codegen-type-name-override: CustomTypeName - properties: - id: - type: string - - # Test type-override at schema level - ExternalType: - type: string - x-oapi-codegen-type-override: "uuid.UUID;github.com/google/uuid" - - # Test field-level extensions - User: - type: object - properties: - # Test name override - user_id: - type: string - x-oapi-codegen-name-override: UserID - # Test type override - created_at: - type: string - x-oapi-codegen-type-override: "time.Time;time" - # Test skip optional pointer - description: - type: string - x-oapi-codegen-skip-optional-pointer: true - # Test omitempty control - status: - type: string - x-oapi-codegen-omitempty: false - # Test omitzero - count: - type: integer - x-oapi-codegen-omitzero: true - # Test order (count should come before status) - age: - type: integer - x-oapi-codegen-order: 1 - name: - type: string - x-oapi-codegen-order: 0 - # Test deprecated reason - old_field: - type: string - x-oapi-codegen-deprecated-reason: "Use new_field instead" - - # Test enum with custom var names - Status: - type: string - enum: - - active - - inactive - - pending - x-oapi-codegen-enum-varnames: - - Active - - Inactive - - Pending -` - - doc, err := libopenapi.NewDocument([]byte(spec)) - if err != nil { - t.Fatalf("Failed to parse spec: %v", err) - } - - cfg := Configuration{ - PackageName: "output", - } - - code, err := Generate(doc, nil, cfg) - if err != nil { - t.Fatalf("Generate failed: %v", err) - } - - t.Logf("Generated code:\n%s", code) - - // Verify type-name-override - if !strings.Contains(code, "type CustomTypeName") { - t.Error("Expected CustomTypeName type from type-name-override") - } - - // Verify type-override at schema level creates alias - if !strings.Contains(code, "= uuid.UUID") { - t.Error("Expected type alias to uuid.UUID from type-override") - } - if !strings.Contains(code, `"github.com/google/uuid"`) { - t.Error("Expected uuid import") - } - - // Verify name override - if !strings.Contains(code, "UserID") { - t.Error("Expected UserID field from name-override") - } - - // Verify type override on field - if !strings.Contains(code, "time.Time") { - t.Error("Expected time.Time from field type-override") - } - if !strings.Contains(code, `"time"`) { - t.Error("Expected time import") - } - - // Verify skip-optional-pointer (description should be string, not *string) - // The field should appear as just "string", not "*string" - if strings.Contains(code, "Description *string") || strings.Contains(code, "Description *string") { - t.Error("Expected description to not be a pointer due to skip-optional-pointer") - } - if !strings.Contains(code, "Description string") && !strings.Contains(code, "Description string") { - t.Error("Expected description to be a non-pointer string") - } - - // Verify omitzero - if !strings.Contains(code, "omitzero") { - t.Error("Expected omitzero in struct tags") - } - - // Verify deprecated reason in doc - if !strings.Contains(code, "Deprecated:") { - t.Error("Expected Deprecated: in documentation") - } - - // Verify enum with custom var names - if !strings.Contains(code, "Status_Active") { - t.Error("Expected Status_Active from custom enum var names") - } - if !strings.Contains(code, "Status_Inactive") { - t.Error("Expected Status_Inactive from custom enum var names") - } - if !strings.Contains(code, "Status_Pending") { - t.Error("Expected Status_Pending from custom enum var names") - } -} - -func TestLegacyExtensionIntegration(t *testing.T) { - spec := ` -openapi: "3.1.0" -info: - title: Legacy Extension Test API - version: "1.0" -paths: {} -components: - schemas: - User: - type: object - properties: - # Test legacy x-go-type - id: - type: string - x-go-type: mypackage.ID - # Test legacy x-go-name - user_name: - type: string - x-go-name: Username -` - - doc, err := libopenapi.NewDocument([]byte(spec)) - if err != nil { - t.Fatalf("Failed to parse spec: %v", err) - } - - cfg := Configuration{ - PackageName: "output", - } - - code, err := Generate(doc, nil, cfg) - if err != nil { - t.Fatalf("Generate failed: %v", err) - } - - t.Logf("Generated code:\n%s", code) - - // Verify legacy x-go-type works - if !strings.Contains(code, "mypackage.ID") { - t.Error("Expected mypackage.ID from legacy x-go-type") - } - - // Verify legacy x-go-name works - if !strings.Contains(code, "Username") { - t.Error("Expected Username from legacy x-go-name") - } -} diff --git a/experimental/internal/codegen/extension_test.go b/experimental/internal/codegen/extension_test.go deleted file mode 100644 index c0f615fc41..0000000000 --- a/experimental/internal/codegen/extension_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/pb33f/libopenapi/orderedmap" - "go.yaml.in/yaml/v4" -) - -func TestParseTypeOverride(t *testing.T) { - tests := []struct { - name string - input string - wantType string - wantPath string - wantAlias string - }{ - { - name: "simple type", - input: "int64", - wantType: "int64", - }, - { - name: "type with import", - input: "uuid.UUID;github.com/google/uuid", - wantType: "uuid.UUID", - wantPath: "github.com/google/uuid", - }, - { - name: "type with aliased import", - input: "foo.Type;foo github.com/bar/foo/v2", - wantType: "foo.Type", - wantPath: "github.com/bar/foo/v2", - wantAlias: "foo", - }, - { - name: "type with spaces", - input: " decimal.Decimal ; github.com/shopspring/decimal ", - wantType: "decimal.Decimal", - wantPath: "github.com/shopspring/decimal", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseTypeOverride(tt.input) - if err != nil { - t.Fatalf("parseTypeOverride() error = %v", err) - } - if got.TypeName != tt.wantType { - t.Errorf("TypeName = %q, want %q", got.TypeName, tt.wantType) - } - if got.ImportPath != tt.wantPath { - t.Errorf("ImportPath = %q, want %q", got.ImportPath, tt.wantPath) - } - if got.ImportAlias != tt.wantAlias { - t.Errorf("ImportAlias = %q, want %q", got.ImportAlias, tt.wantAlias) - } - }) - } -} - -func TestParseExtensions(t *testing.T) { - // Create a test extensions map - extensions := orderedmap.New[string, *yaml.Node]() - - // Add a type override extension - typeOverrideNode := &yaml.Node{} - typeOverrideNode.SetString("uuid.UUID;github.com/google/uuid") - extensions.Set(ExtTypeOverride, typeOverrideNode) - - // Add a name override extension - nameOverrideNode := &yaml.Node{} - nameOverrideNode.SetString("CustomFieldName") - extensions.Set(ExtNameOverride, nameOverrideNode) - - // Add omitempty extension - omitEmptyNode := &yaml.Node{} - if err := omitEmptyNode.Encode(true); err != nil { - t.Fatalf("Failed to encode omitEmptyNode: %v", err) - } - extensions.Set(ExtOmitEmpty, omitEmptyNode) - - ext, err := ParseExtensions(extensions, "#/test/path") - if err != nil { - t.Fatalf("ParseExtensions() error = %v", err) - } - - // Check type override - if ext.TypeOverride == nil { - t.Fatal("TypeOverride should not be nil") - } - if ext.TypeOverride.TypeName != "uuid.UUID" { - t.Errorf("TypeOverride.TypeName = %q, want %q", ext.TypeOverride.TypeName, "uuid.UUID") - } - if ext.TypeOverride.ImportPath != "github.com/google/uuid" { - t.Errorf("TypeOverride.ImportPath = %q, want %q", ext.TypeOverride.ImportPath, "github.com/google/uuid") - } - - // Check name override - if ext.NameOverride != "CustomFieldName" { - t.Errorf("NameOverride = %q, want %q", ext.NameOverride, "CustomFieldName") - } - - // Check omitempty - if ext.OmitEmpty == nil || *ext.OmitEmpty != true { - t.Errorf("OmitEmpty = %v, want true", ext.OmitEmpty) - } -} - -func TestParseExtensionsLegacy(t *testing.T) { - // Create a test extensions map with legacy names - extensions := orderedmap.New[string, *yaml.Node]() - - // Add legacy x-go-type extension - goTypeNode := &yaml.Node{} - goTypeNode.SetString("time.Time") - extensions.Set("x-go-type", goTypeNode) - - // Add legacy x-go-type-import extension - goImportNode := &yaml.Node{} - goImportNode.SetString("time") - extensions.Set("x-go-type-import", goImportNode) - - // Add legacy x-go-name extension - goNameNode := &yaml.Node{} - goNameNode.SetString("LegacyFieldName") - extensions.Set("x-go-name", goNameNode) - - ext, err := ParseExtensions(extensions, "#/test/path") - if err != nil { - t.Fatalf("ParseExtensions() error = %v", err) - } - - // Check type override (from legacy) - if ext.TypeOverride == nil { - t.Fatal("TypeOverride should not be nil") - } - if ext.TypeOverride.TypeName != "time.Time" { - t.Errorf("TypeOverride.TypeName = %q, want %q", ext.TypeOverride.TypeName, "time.Time") - } - if ext.TypeOverride.ImportPath != "time" { - t.Errorf("TypeOverride.ImportPath = %q, want %q", ext.TypeOverride.ImportPath, "time") - } - - // Check name override (from legacy) - if ext.NameOverride != "LegacyFieldName" { - t.Errorf("NameOverride = %q, want %q", ext.NameOverride, "LegacyFieldName") - } -} - -func TestParseExtensionsEnumVarNames(t *testing.T) { - extensions := orderedmap.New[string, *yaml.Node]() - - // Add enum var names as a sequence - enumNamesNode := &yaml.Node{ - Kind: yaml.SequenceNode, - Content: []*yaml.Node{ - {Kind: yaml.ScalarNode, Value: "Active"}, - {Kind: yaml.ScalarNode, Value: "Inactive"}, - {Kind: yaml.ScalarNode, Value: "Pending"}, - }, - } - extensions.Set(ExtEnumVarNames, enumNamesNode) - - ext, err := ParseExtensions(extensions, "#/test/path") - if err != nil { - t.Fatalf("ParseExtensions() error = %v", err) - } - - if len(ext.EnumVarNames) != 3 { - t.Fatalf("EnumVarNames length = %d, want 3", len(ext.EnumVarNames)) - } - expected := []string{"Active", "Inactive", "Pending"} - for i, name := range ext.EnumVarNames { - if name != expected[i] { - t.Errorf("EnumVarNames[%d] = %q, want %q", i, name, expected[i]) - } - } -} diff --git a/experimental/internal/codegen/gather.go b/experimental/internal/codegen/gather.go deleted file mode 100644 index 0644ed7897..0000000000 --- a/experimental/internal/codegen/gather.go +++ /dev/null @@ -1,621 +0,0 @@ -package codegen - -import ( - "fmt" - "log/slog" - - "github.com/pb33f/libopenapi" - "github.com/pb33f/libopenapi/datamodel/high/base" - v3 "github.com/pb33f/libopenapi/datamodel/high/v3" -) - -// GatherResult contains the results of gathering from an OpenAPI document. -type GatherResult struct { - Schemas []*SchemaDescriptor - ParamTracker *ParamUsageTracker -} - -// GatherSchemas traverses an OpenAPI document and collects all schemas into a list. -func GatherSchemas(doc libopenapi.Document, contentTypeMatcher *ContentTypeMatcher) ([]*SchemaDescriptor, error) { - result, err := GatherAll(doc, contentTypeMatcher) - if err != nil { - return nil, err - } - return result.Schemas, nil -} - -// GatherAll traverses an OpenAPI document and collects all schemas and parameter usage. -func GatherAll(doc libopenapi.Document, contentTypeMatcher *ContentTypeMatcher) (*GatherResult, error) { - model, err := doc.BuildV3Model() - if err != nil { - return nil, fmt.Errorf("building v3 model: %w", err) - } - if model == nil { - return nil, fmt.Errorf("failed to build v3 model") - } - - g := &gatherer{ - schemas: make([]*SchemaDescriptor, 0), - contentTypeMatcher: contentTypeMatcher, - paramTracker: NewParamUsageTracker(), - } - - g.gatherFromDocument(&model.Model) - return &GatherResult{ - Schemas: g.schemas, - ParamTracker: g.paramTracker, - }, nil -} - -type gatherer struct { - schemas []*SchemaDescriptor - contentTypeMatcher *ContentTypeMatcher - paramTracker *ParamUsageTracker - // Context for the current operation being gathered (for nicer naming) - currentOperationID string - currentContentType string -} - -func (g *gatherer) gatherFromDocument(doc *v3.Document) { - // Gather from components/schemas - if doc.Components != nil && doc.Components.Schemas != nil { - for pair := doc.Components.Schemas.First(); pair != nil; pair = pair.Next() { - name := pair.Key() - schemaProxy := pair.Value() - path := SchemaPath{"components", "schemas", name} - g.gatherFromSchemaProxy(schemaProxy, path, nil) - } - } - - // Gather from paths - if doc.Paths != nil && doc.Paths.PathItems != nil { - for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { - pathStr := pair.Key() - pathItem := pair.Value() - g.gatherFromPathItem(pathItem, SchemaPath{"paths", pathStr}) - } - } - - // Gather from webhooks (3.1+) - if doc.Webhooks != nil { - for pair := doc.Webhooks.First(); pair != nil; pair = pair.Next() { - name := pair.Key() - pathItem := pair.Value() - g.gatherFromPathItem(pathItem, SchemaPath{"webhooks", name}) - } - } -} - -func (g *gatherer) gatherFromPathItem(pathItem *v3.PathItem, basePath SchemaPath) { - if pathItem == nil { - return - } - - // Path-level parameters - for i, param := range pathItem.Parameters { - g.gatherFromParameter(param, basePath.Append("parameters", fmt.Sprintf("%d", i))) - } - - // Operations - ops := pathItem.GetOperations() - if ops != nil { - for pair := ops.First(); pair != nil; pair = pair.Next() { - method := pair.Key() - op := pair.Value() - g.gatherFromOperation(op, basePath.Append(method)) - } - } -} - -func (g *gatherer) gatherFromOperation(op *v3.Operation, basePath SchemaPath) { - if op == nil { - return - } - - // Set operation context for nicer naming - prevOperationID := g.currentOperationID - if op.OperationId != "" { - g.currentOperationID = op.OperationId - } - - // Parameters - for i, param := range op.Parameters { - g.gatherFromParameter(param, basePath.Append("parameters", fmt.Sprintf("%d", i))) - } - - // Request body - if op.RequestBody != nil { - g.gatherFromRequestBody(op.RequestBody, basePath.Append("requestBody")) - } - - // Responses - if op.Responses != nil && op.Responses.Codes != nil { - for pair := op.Responses.Codes.First(); pair != nil; pair = pair.Next() { - code := pair.Key() - response := pair.Value() - g.gatherFromResponse(response, basePath.Append("responses", code)) - } - } - - // Callbacks - if op.Callbacks != nil { - for pair := op.Callbacks.First(); pair != nil; pair = pair.Next() { - name := pair.Key() - callback := pair.Value() - g.gatherFromCallback(callback, basePath.Append("callbacks", name)) - } - } - - // Restore previous operation context - g.currentOperationID = prevOperationID -} - -func (g *gatherer) gatherFromParameter(param *v3.Parameter, basePath SchemaPath) { - if param == nil { - return - } - - // Track parameter styling usage for code generation - if g.paramTracker != nil && param.Schema != nil { - // Determine style (with defaults based on location) - style := param.Style - if style == "" { - style = DefaultParamStyle(param.In) - } - - // Determine explode (with defaults based on location) - explode := DefaultParamExplode(param.In) - if param.Explode != nil { - explode = *param.Explode - } - - // Record both style (client) and bind (server) usage - g.paramTracker.RecordParam(style, explode) - } - - if param.Schema != nil { - g.gatherFromSchemaProxy(param.Schema, basePath.Append("schema"), nil) - } - - // Parameter can also have content with schemas - if param.Content != nil { - for pair := param.Content.First(); pair != nil; pair = pair.Next() { - contentType := pair.Key() - mediaType := pair.Value() - g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) - } - } -} - -func (g *gatherer) gatherFromRequestBody(rb *v3.RequestBody, basePath SchemaPath) { - if rb == nil || rb.Content == nil { - return - } - - for pair := rb.Content.First(); pair != nil; pair = pair.Next() { - contentType := pair.Key() - // Skip content types that don't match the configured patterns - if g.contentTypeMatcher != nil && !g.contentTypeMatcher.Matches(contentType) { - continue - } - // Set content type context - prevContentType := g.currentContentType - g.currentContentType = contentType - - mediaType := pair.Value() - g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) - - g.currentContentType = prevContentType - } -} - -func (g *gatherer) gatherFromResponse(response *v3.Response, basePath SchemaPath) { - if response == nil { - return - } - - if response.Content != nil { - for pair := response.Content.First(); pair != nil; pair = pair.Next() { - contentType := pair.Key() - // Skip content types that don't match the configured patterns - if g.contentTypeMatcher != nil && !g.contentTypeMatcher.Matches(contentType) { - continue - } - // Set content type context - prevContentType := g.currentContentType - g.currentContentType = contentType - - mediaType := pair.Value() - g.gatherFromMediaType(mediaType, basePath.Append("content", contentType)) - - g.currentContentType = prevContentType - } - } - - // Response headers can have schemas - if response.Headers != nil { - for pair := response.Headers.First(); pair != nil; pair = pair.Next() { - name := pair.Key() - header := pair.Value() - if header != nil && header.Schema != nil { - g.gatherFromSchemaProxy(header.Schema, basePath.Append("headers", name, "schema"), nil) - } - } - } -} - -func (g *gatherer) gatherFromMediaType(mt *v3.MediaType, basePath SchemaPath) { - if mt == nil || mt.Schema == nil { - return - } - g.gatherFromSchemaProxy(mt.Schema, basePath.Append("schema"), nil) -} - -func (g *gatherer) gatherFromCallback(callback *v3.Callback, basePath SchemaPath) { - if callback == nil || callback.Expression == nil { - return - } - - for pair := callback.Expression.First(); pair != nil; pair = pair.Next() { - expr := pair.Key() - pathItem := pair.Value() - g.gatherFromPathItem(pathItem, basePath.Append(expr)) - } -} - -func (g *gatherer) gatherFromSchemaProxy(proxy *base.SchemaProxy, path SchemaPath, parent *SchemaDescriptor) *SchemaDescriptor { - if proxy == nil { - return nil - } - - // Check if this is a reference - isRef := proxy.IsReference() - ref := "" - if isRef { - ref = proxy.GetReference() - } - - // Get the resolved schema - schema := proxy.Schema() - - // Check if schema has extensions that require type generation - hasTypeOverride := schema != nil && schema.Extensions != nil && hasExtension(schema.Extensions, ExtTypeOverride, legacyExtGoType) - hasTypeNameOverride := schema != nil && schema.Extensions != nil && hasExtension(schema.Extensions, ExtTypeNameOverride, legacyExtGoTypeName) - - // Only gather schemas that need a generated type - // References are always gathered (they point to real schemas) - // Simple types (primitives without enum) are skipped - // Inline nullable primitives (under properties/) don't need types - they use Nullable[T] directly - // Schemas with type-override or type-name-override extensions always need types - isInlineProperty := path.ContainsProperties() - skipInlineNullablePrimitive := isInlineProperty && isNullablePrimitive(schema) - needsType := isRef || needsGeneratedType(schema) || hasTypeOverride || hasTypeNameOverride - if needsType && !skipInlineNullablePrimitive { - desc := &SchemaDescriptor{ - Path: path, - Parent: parent, - Ref: ref, - Schema: schema, - OperationID: g.currentOperationID, - ContentType: g.currentContentType, - } - - // Parse extensions from the schema - if schema != nil && schema.Extensions != nil { - ext, err := ParseExtensions(schema.Extensions, path.String()) - if err != nil { - slog.Warn("failed to parse extensions", - "path", path.String(), - "error", err) - } else { - desc.Extensions = ext - } - } - - g.schemas = append(g.schemas, desc) - - // Don't recurse into references - they point to schemas we'll gather elsewhere - if isRef { - return desc - } - - // Recurse into schema structure - if schema != nil { - g.gatherFromSchema(schema, path, desc) - } - return desc - } else if schema != nil { - // Even if we don't gather this schema, we still need to recurse - // to find any nested complex schemas (e.g., array items that are objects) - g.gatherFromSchema(schema, path, nil) - } - return nil -} - -// gatherSchemaDescriptorOnly creates a descriptor for field extraction without adding it -// to the schemas list (i.e., no type will be generated for it). -// This is used for inline allOf members whose fields are flattened into the parent. -func (g *gatherer) gatherSchemaDescriptorOnly(proxy *base.SchemaProxy, path SchemaPath, parent *SchemaDescriptor) *SchemaDescriptor { - if proxy == nil { - return nil - } - - schema := proxy.Schema() - if schema == nil { - return nil - } - - desc := &SchemaDescriptor{ - Path: path, - Parent: parent, - Schema: schema, - } - - // Parse extensions from the schema - if schema.Extensions != nil { - ext, err := ParseExtensions(schema.Extensions, path.String()) - if err != nil { - slog.Warn("failed to parse extensions", - "path", path.String(), - "error", err) - } else { - desc.Extensions = ext - } - } - - // Still recurse to gather any nested complex schemas that DO need types - // (e.g., nested objects within properties) - g.gatherFromSchema(schema, path, desc) - - return desc -} - -// needsGeneratedType returns true if a schema requires a generated Go type. -// Simple primitive types (string, integer, number, boolean) without enums -// don't need generated types - they map directly to Go builtins. -// However, nullable primitives DO need generated types (Nullable[T]). -func needsGeneratedType(schema *base.Schema) bool { - if schema == nil { - return false - } - - // Nullable primitives need a generated type (Nullable[T]) - if isNullablePrimitive(schema) { - return true - } - - // Enums always need a generated type - if len(schema.Enum) > 0 { - return true - } - - // Objects need a generated type - if schema.Properties != nil && schema.Properties.Len() > 0 { - return true - } - - // Check explicit type - types := schema.Type - for _, t := range types { - if t == "object" { - return true - } - } - - // Composition types need generated types - if len(schema.AllOf) > 0 || len(schema.AnyOf) > 0 || len(schema.OneOf) > 0 { - return true - } - - // Arrays with complex items need generated types for the array type itself - // But we handle items separately in gatherFromSchema - if schema.Items != nil && schema.Items.A != nil { - itemSchema := schema.Items.A.Schema() - if needsGeneratedType(itemSchema) { - return true - } - } - - // AdditionalProperties with complex schema needs a type - if schema.AdditionalProperties != nil && schema.AdditionalProperties.A != nil { - addSchema := schema.AdditionalProperties.A.Schema() - if needsGeneratedType(addSchema) { - return true - } - } - - // Simple primitives (string, integer, number, boolean) without enum - // don't need generated types - return false -} - -// isNullablePrimitive returns true if the schema is a nullable primitive type. -// Nullable primitives need Nullable[T] wrapper types. -func isNullablePrimitive(schema *base.Schema) bool { - if schema == nil { - return false - } - - // Check for nullable - isNullable := false - // OpenAPI 3.1 style: type array includes "null" - for _, t := range schema.Type { - if t == "null" { - isNullable = true - break - } - } - // OpenAPI 3.0 style: nullable: true - if schema.Nullable != nil && *schema.Nullable { - isNullable = true - } - - if !isNullable { - return false - } - - // Check if it's a primitive type (not object, array, or composition) - if schema.Properties != nil && schema.Properties.Len() > 0 { - return false // object with properties - } - if len(schema.AllOf) > 0 || len(schema.AnyOf) > 0 || len(schema.OneOf) > 0 { - return false // composition type - } - if schema.Items != nil { - return false // array - } - - // Get the primary type - for _, t := range schema.Type { - switch t { - case "string", "integer", "number", "boolean": - return true - case "object": - return false - case "array": - return false - } - } - - return false -} - -func (g *gatherer) gatherFromSchema(schema *base.Schema, basePath SchemaPath, parent *SchemaDescriptor) { - if schema == nil { - return - } - - // Properties - if schema.Properties != nil { - if parent != nil { - parent.Properties = make(map[string]*SchemaDescriptor) - } - for pair := schema.Properties.First(); pair != nil; pair = pair.Next() { - propName := pair.Key() - propProxy := pair.Value() - propPath := basePath.Append("properties", propName) - propDesc := g.gatherFromSchemaProxy(propProxy, propPath, parent) - if parent != nil && propDesc != nil { - parent.Properties[propName] = propDesc - } - } - } - - // Items (array element schema) - if schema.Items != nil && schema.Items.A != nil { - itemsPath := basePath.Append("items") - itemsDesc := g.gatherFromSchemaProxy(schema.Items.A, itemsPath, parent) - if parent != nil && itemsDesc != nil { - parent.Items = itemsDesc - } - } - - // AllOf - inline object members don't need separate types since fields are flattened into parent - // However, inline oneOf/anyOf members DO need union types generated - for i, proxy := range schema.AllOf { - allOfPath := basePath.Append("allOf", fmt.Sprintf("%d", i)) - var allOfDesc *SchemaDescriptor - if proxy.IsReference() { - // References still need to be gathered normally - allOfDesc = g.gatherFromSchemaProxy(proxy, allOfPath, parent) - } else { - memberSchema := proxy.Schema() - // If the allOf member is itself a oneOf/anyOf, we need to generate a union type - if memberSchema != nil && (len(memberSchema.OneOf) > 0 || len(memberSchema.AnyOf) > 0) { - allOfDesc = g.gatherFromSchemaProxy(proxy, allOfPath, parent) - } else { - // Simple inline objects: create descriptor for field extraction but don't generate a type - allOfDesc = g.gatherSchemaDescriptorOnly(proxy, allOfPath, parent) - } - } - if parent != nil && allOfDesc != nil { - parent.AllOf = append(parent.AllOf, allOfDesc) - } - } - - // AnyOf - for i, proxy := range schema.AnyOf { - anyOfPath := basePath.Append("anyOf", fmt.Sprintf("%d", i)) - anyOfDesc := g.gatherFromSchemaProxy(proxy, anyOfPath, parent) - if parent != nil && anyOfDesc != nil { - parent.AnyOf = append(parent.AnyOf, anyOfDesc) - } - } - - // OneOf - for i, proxy := range schema.OneOf { - oneOfPath := basePath.Append("oneOf", fmt.Sprintf("%d", i)) - oneOfDesc := g.gatherFromSchemaProxy(proxy, oneOfPath, parent) - if parent != nil && oneOfDesc != nil { - parent.OneOf = append(parent.OneOf, oneOfDesc) - } - } - - // AdditionalProperties (if it's a schema, not a boolean) - if schema.AdditionalProperties != nil && schema.AdditionalProperties.A != nil { - addPropsPath := basePath.Append("additionalProperties") - addPropsDesc := g.gatherFromSchemaProxy(schema.AdditionalProperties.A, addPropsPath, parent) - if parent != nil && addPropsDesc != nil { - parent.AdditionalProps = addPropsDesc - } - } - - // Not - if schema.Not != nil { - g.gatherFromSchemaProxy(schema.Not, basePath.Append("not"), parent) - } - - // PrefixItems (3.1 tuple validation) - for i, proxy := range schema.PrefixItems { - g.gatherFromSchemaProxy(proxy, basePath.Append("prefixItems", fmt.Sprintf("%d", i)), parent) - } - - // Contains (3.1) - if schema.Contains != nil { - g.gatherFromSchemaProxy(schema.Contains, basePath.Append("contains"), parent) - } - - // If/Then/Else (3.1) - if schema.If != nil { - g.gatherFromSchemaProxy(schema.If, basePath.Append("if"), parent) - } - if schema.Then != nil { - g.gatherFromSchemaProxy(schema.Then, basePath.Append("then"), parent) - } - if schema.Else != nil { - g.gatherFromSchemaProxy(schema.Else, basePath.Append("else"), parent) - } - - // DependentSchemas (3.1) - if schema.DependentSchemas != nil { - for pair := schema.DependentSchemas.First(); pair != nil; pair = pair.Next() { - name := pair.Key() - proxy := pair.Value() - g.gatherFromSchemaProxy(proxy, basePath.Append("dependentSchemas", name), parent) - } - } - - // PatternProperties (3.1) - if schema.PatternProperties != nil { - for pair := schema.PatternProperties.First(); pair != nil; pair = pair.Next() { - pattern := pair.Key() - proxy := pair.Value() - g.gatherFromSchemaProxy(proxy, basePath.Append("patternProperties", pattern), parent) - } - } - - // PropertyNames (3.1) - if schema.PropertyNames != nil { - g.gatherFromSchemaProxy(schema.PropertyNames, basePath.Append("propertyNames"), parent) - } - - // UnevaluatedItems (3.1) - if schema.UnevaluatedItems != nil { - g.gatherFromSchemaProxy(schema.UnevaluatedItems, basePath.Append("unevaluatedItems"), parent) - } - - // UnevaluatedProperties (3.1) - can be schema or bool - if schema.UnevaluatedProperties != nil && schema.UnevaluatedProperties.A != nil { - g.gatherFromSchemaProxy(schema.UnevaluatedProperties.A, basePath.Append("unevaluatedProperties"), parent) - } -} diff --git a/experimental/internal/codegen/gather_operations.go b/experimental/internal/codegen/gather_operations.go deleted file mode 100644 index 0492bbb433..0000000000 --- a/experimental/internal/codegen/gather_operations.go +++ /dev/null @@ -1,864 +0,0 @@ -package codegen - -import ( - "fmt" - "sort" - "strings" - - "github.com/pb33f/libopenapi" - "github.com/pb33f/libopenapi/datamodel/high/base" - v3 "github.com/pb33f/libopenapi/datamodel/high/v3" -) - -// GatherOperations traverses an OpenAPI document and collects all operations. -func GatherOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { - model, err := doc.BuildV3Model() - if err != nil { - return nil, fmt.Errorf("building v3 model: %w", err) - } - if model == nil { - return nil, fmt.Errorf("failed to build v3 model") - } - - g := &operationGatherer{ - paramTracker: paramTracker, - } - - return g.gatherFromDocument(&model.Model) -} - -type operationGatherer struct { - paramTracker *ParamUsageTracker -} - -func (g *operationGatherer) gatherFromDocument(doc *v3.Document) ([]*OperationDescriptor, error) { - var operations []*OperationDescriptor - - if doc.Paths == nil || doc.Paths.PathItems == nil { - return operations, nil - } - - // Collect paths in sorted order for deterministic output - var paths []string - for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { - paths = append(paths, pair.Key()) - } - sort.Strings(paths) - - for _, pathStr := range paths { - pathItem := doc.Paths.PathItems.GetOrZero(pathStr) - if pathItem == nil { - continue - } - - // Gather path-level parameters (shared by all operations on this path) - globalParams, err := g.gatherParameters(pathItem.Parameters) - if err != nil { - return nil, fmt.Errorf("error gathering path-level parameters for %s: %w", pathStr, err) - } - - // Process each operation on this path - ops := pathItem.GetOperations() - if ops == nil { - continue - } - - // Collect methods in sorted order - var methods []string - for pair := ops.First(); pair != nil; pair = pair.Next() { - methods = append(methods, pair.Key()) - } - sort.Strings(methods) - - for _, method := range methods { - op := ops.GetOrZero(method) - if op == nil { - continue - } - - opDesc, err := g.gatherOperation(method, pathStr, op, globalParams) - if err != nil { - return nil, fmt.Errorf("error gathering operation %s %s: %w", method, pathStr, err) - } - operations = append(operations, opDesc) - } - } - - return operations, nil -} - -func (g *operationGatherer) gatherOperation(method, path string, op *v3.Operation, globalParams []*ParameterDescriptor) (*OperationDescriptor, error) { - // Determine operation ID - operationID := op.OperationId - if operationID == "" { - operationID = generateOperationID(method, path) - } - goOperationID := ToGoIdentifier(operationID) - - // Gather operation-level parameters - localParams, err := g.gatherParameters(op.Parameters) - if err != nil { - return nil, fmt.Errorf("error gathering parameters: %w", err) - } - - // Combine global and local parameters (local overrides global) - allParams := combineParameters(globalParams, localParams) - - // Sort path params to match order in path - pathParams := filterParamsByLocation(allParams, "path") - pathParams, err = sortPathParamsByPath(path, pathParams) - if err != nil { - return nil, fmt.Errorf("error sorting path params: %w", err) - } - - // Gather request bodies - bodies, err := g.gatherRequestBodies(operationID, op.RequestBody) - if err != nil { - return nil, fmt.Errorf("error gathering request bodies: %w", err) - } - - // Gather responses - responses, err := g.gatherResponses(operationID, op.Responses) - if err != nil { - return nil, fmt.Errorf("error gathering responses: %w", err) - } - - // Gather security requirements - security := g.gatherSecurity(op.Security) - - queryParams := filterParamsByLocation(allParams, "query") - headerParams := filterParamsByLocation(allParams, "header") - cookieParams := filterParamsByLocation(allParams, "cookie") - - hasParams := len(queryParams)+len(headerParams)+len(cookieParams) > 0 - - desc := &OperationDescriptor{ - OperationID: operationID, - GoOperationID: goOperationID, - Method: strings.ToUpper(method), - Path: path, - Summary: op.Summary, - Description: op.Description, - - PathParams: pathParams, - QueryParams: queryParams, - HeaderParams: headerParams, - CookieParams: cookieParams, - - Bodies: bodies, - Responses: responses, - Security: security, - - HasBody: len(bodies) > 0, - HasParams: hasParams, - ParamsTypeName: goOperationID + "Params", - - Spec: op, - } - - return desc, nil -} - -func (g *operationGatherer) gatherParameters(params []*v3.Parameter) ([]*ParameterDescriptor, error) { - var result []*ParameterDescriptor - - for _, param := range params { - if param == nil { - continue - } - - desc, err := g.gatherParameter(param) - if err != nil { - return nil, fmt.Errorf("error gathering parameter %s: %w", param.Name, err) - } - result = append(result, desc) - } - - return result, nil -} - -func (g *operationGatherer) gatherParameter(param *v3.Parameter) (*ParameterDescriptor, error) { - // Determine style and explode (with defaults based on location) - style := param.Style - if style == "" { - style = DefaultParamStyle(param.In) - } - - explode := DefaultParamExplode(param.In) - if param.Explode != nil { - explode = *param.Explode - } - - // Record param usage for function generation - if g.paramTracker != nil { - g.paramTracker.RecordParam(style, explode) - } - - // Determine encoding mode - isStyled := param.Schema != nil - isJSON := false - isPassThrough := false - - if param.Content != nil && param.Content.Len() > 0 { - // Parameter uses content encoding - isStyled = false - for pair := param.Content.First(); pair != nil; pair = pair.Next() { - contentType := pair.Key() - if IsMediaTypeJSON(contentType) { - isJSON = true - break - } - } - if !isJSON { - isPassThrough = true - } - } - - // Get type declaration from schema - typeDecl := "string" // Default - var schemaDesc *SchemaDescriptor - if param.Schema != nil { - schema := param.Schema.Schema() - if schema != nil { - schemaDesc = &SchemaDescriptor{ - Schema: schema, - } - typeDecl = schemaToGoType(schema) - } - } - - goName := ToCamelCase(param.Name) - - // Handle *bool for Required - required := false - if param.Required != nil { - required = *param.Required - } - - desc := &ParameterDescriptor{ - Name: param.Name, - GoName: goName, - Location: param.In, - Required: required, - - Style: style, - Explode: explode, - - Schema: schemaDesc, - TypeDecl: typeDecl, - - StyleFunc: ComputeStyleFunc(style, explode), - BindFunc: ComputeBindFunc(style, explode), - - IsStyled: isStyled, - IsPassThrough: isPassThrough, - IsJSON: isJSON, - - Spec: param, - } - - return desc, nil -} - -func (g *operationGatherer) gatherRequestBodies(operationID string, bodyRef *v3.RequestBody) ([]*RequestBodyDescriptor, error) { - if bodyRef == nil { - return nil, nil - } - - var bodies []*RequestBodyDescriptor - - if bodyRef.Content == nil { - return bodies, nil - } - - // Collect content types in sorted order - var contentTypes []string - for pair := bodyRef.Content.First(); pair != nil; pair = pair.Next() { - contentTypes = append(contentTypes, pair.Key()) - } - sort.Strings(contentTypes) - - // Determine which is the default (application/json if present) - hasApplicationJSON := false - for _, ct := range contentTypes { - if ct == "application/json" { - hasApplicationJSON = true - break - } - } - - for _, contentType := range contentTypes { - mediaType := bodyRef.Content.GetOrZero(contentType) - if mediaType == nil { - continue - } - - nameTag := ComputeBodyNameTag(contentType) - isDefault := contentType == "application/json" || (!hasApplicationJSON && contentType == contentTypes[0]) - - var schemaDesc *SchemaDescriptor - if mediaType.Schema != nil { - schemaDesc = schemaProxyToDescriptor(mediaType.Schema) - } - - funcSuffix := "" - if !isDefault && nameTag != "" { - funcSuffix = "With" + nameTag + "Body" - } - - goTypeName := operationID + nameTag + "RequestBody" - if nameTag == "" { - goTypeName = operationID + "RequestBody" - } - - // Handle *bool for Required - bodyRequired := false - if bodyRef.Required != nil { - bodyRequired = *bodyRef.Required - } - - desc := &RequestBodyDescriptor{ - ContentType: contentType, - Required: bodyRequired, - Schema: schemaDesc, - - NameTag: nameTag, - GoTypeName: goTypeName, - FuncSuffix: funcSuffix, - IsDefault: isDefault, - IsJSON: IsMediaTypeJSON(contentType), - } - - // Gather encoding options for form data - if mediaType.Encoding != nil && mediaType.Encoding.Len() > 0 { - desc.Encoding = make(map[string]RequestBodyEncoding) - for pair := mediaType.Encoding.First(); pair != nil; pair = pair.Next() { - enc := pair.Value() - desc.Encoding[pair.Key()] = RequestBodyEncoding{ - ContentType: enc.ContentType, - Style: enc.Style, - Explode: enc.Explode, - } - } - } - - bodies = append(bodies, desc) - } - - return bodies, nil -} - -func (g *operationGatherer) gatherResponses(operationID string, responses *v3.Responses) ([]*ResponseDescriptor, error) { - if responses == nil { - return nil, nil - } - - var result []*ResponseDescriptor - - // Gather default response - if responses.Default != nil { - desc, err := g.gatherResponse(operationID, "default", responses.Default) - if err != nil { - return nil, err - } - if desc != nil { - result = append(result, desc) - } - } - - // Gather status code responses - if responses.Codes != nil { - var codes []string - for pair := responses.Codes.First(); pair != nil; pair = pair.Next() { - codes = append(codes, pair.Key()) - } - sort.Strings(codes) - - for _, code := range codes { - respRef := responses.Codes.GetOrZero(code) - if respRef == nil { - continue - } - - desc, err := g.gatherResponse(operationID, code, respRef) - if err != nil { - return nil, err - } - if desc != nil { - result = append(result, desc) - } - } - } - - return result, nil -} - -func (g *operationGatherer) gatherResponse(operationID, statusCode string, resp *v3.Response) (*ResponseDescriptor, error) { - if resp == nil { - return nil, nil - } - - var contents []*ResponseContentDescriptor - if resp.Content != nil { - var contentTypes []string - for pair := resp.Content.First(); pair != nil; pair = pair.Next() { - contentTypes = append(contentTypes, pair.Key()) - } - sort.Strings(contentTypes) - - for _, contentType := range contentTypes { - mediaType := resp.Content.GetOrZero(contentType) - if mediaType == nil { - continue - } - - var schemaDesc *SchemaDescriptor - if mediaType.Schema != nil { - schemaDesc = schemaProxyToDescriptor(mediaType.Schema) - } - - nameTag := ComputeBodyNameTag(contentType) - - contents = append(contents, &ResponseContentDescriptor{ - ContentType: contentType, - Schema: schemaDesc, - NameTag: nameTag, - IsJSON: IsMediaTypeJSON(contentType), - }) - } - } - - var headers []*ResponseHeaderDescriptor - if resp.Headers != nil { - var headerNames []string - for pair := resp.Headers.First(); pair != nil; pair = pair.Next() { - headerNames = append(headerNames, pair.Key()) - } - sort.Strings(headerNames) - - for _, name := range headerNames { - header := resp.Headers.GetOrZero(name) - if header == nil { - continue - } - - var schemaDesc *SchemaDescriptor - if header.Schema != nil { - schemaDesc = schemaProxyToDescriptor(header.Schema) - } - - headers = append(headers, &ResponseHeaderDescriptor{ - Name: name, - GoName: ToCamelCase(name), - Required: header.Required, - Schema: schemaDesc, - }) - } - } - - description := "" - if resp.Description != "" { - description = resp.Description - } - - return &ResponseDescriptor{ - StatusCode: statusCode, - Description: description, - Contents: contents, - Headers: headers, - }, nil -} - -func (g *operationGatherer) gatherSecurity(security []*base.SecurityRequirement) []SecurityRequirement { - if security == nil { - return nil - } - - var result []SecurityRequirement - for _, req := range security { - if req == nil || req.Requirements == nil { - continue - } - for pair := req.Requirements.First(); pair != nil; pair = pair.Next() { - result = append(result, SecurityRequirement{ - Name: pair.Key(), - Scopes: pair.Value(), - }) - } - } - return result -} - -// Helper functions - -func generateOperationID(method, path string) string { - // Generate operation ID from method and path - // GET /users/{id} -> GetUsersId - id := strings.ToLower(method) - for _, part := range strings.Split(path, "/") { - if part == "" { - continue - } - // Remove path parameter braces - part = strings.TrimPrefix(part, "{") - part = strings.TrimSuffix(part, "}") - id += "-" + part - } - return ToCamelCase(id) -} - -func combineParameters(global, local []*ParameterDescriptor) []*ParameterDescriptor { - // Local parameters override global parameters with the same name and location - seen := make(map[string]bool) - var result []*ParameterDescriptor - - for _, p := range local { - key := p.Location + ":" + p.Name - seen[key] = true - result = append(result, p) - } - - for _, p := range global { - key := p.Location + ":" + p.Name - if !seen[key] { - result = append(result, p) - } - } - - return result -} - -func filterParamsByLocation(params []*ParameterDescriptor, location string) []*ParameterDescriptor { - var result []*ParameterDescriptor - for _, p := range params { - if p.Location == location { - result = append(result, p) - } - } - return result -} - -func sortPathParamsByPath(path string, params []*ParameterDescriptor) ([]*ParameterDescriptor, error) { - // Extract parameter names from path in order - var pathParamNames []string - parts := strings.Split(path, "/") - for _, part := range parts { - if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") { - name := strings.TrimPrefix(part, "{") - name = strings.TrimSuffix(name, "}") - pathParamNames = append(pathParamNames, name) - } - } - - // Build a map of params by name - paramMap := make(map[string]*ParameterDescriptor) - for _, p := range params { - paramMap[p.Name] = p - } - - // Sort params according to path order - var result []*ParameterDescriptor - for _, name := range pathParamNames { - if p, ok := paramMap[name]; ok { - result = append(result, p) - } - } - - return result, nil -} - -// GatherWebhookOperations traverses an OpenAPI document and collects operations from webhooks. -func GatherWebhookOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { - model, err := doc.BuildV3Model() - if err != nil { - return nil, fmt.Errorf("building v3 model: %w", err) - } - if model == nil { - return nil, fmt.Errorf("failed to build v3 model") - } - - g := &operationGatherer{ - paramTracker: paramTracker, - } - - return g.gatherWebhooks(&model.Model) -} - -// GatherCallbackOperations traverses an OpenAPI document and collects operations from callbacks. -func GatherCallbackOperations(doc libopenapi.Document, paramTracker *ParamUsageTracker) ([]*OperationDescriptor, error) { - model, err := doc.BuildV3Model() - if err != nil { - return nil, fmt.Errorf("building v3 model: %w", err) - } - if model == nil { - return nil, fmt.Errorf("failed to build v3 model") - } - - g := &operationGatherer{ - paramTracker: paramTracker, - } - - return g.gatherCallbacks(&model.Model) -} - -func (g *operationGatherer) gatherWebhooks(doc *v3.Document) ([]*OperationDescriptor, error) { - var operations []*OperationDescriptor - - if doc.Webhooks == nil || doc.Webhooks.Len() == 0 { - return operations, nil - } - - // Collect webhook names in sorted order for deterministic output - var webhookNames []string - for pair := doc.Webhooks.First(); pair != nil; pair = pair.Next() { - webhookNames = append(webhookNames, pair.Key()) - } - sort.Strings(webhookNames) - - for _, webhookName := range webhookNames { - pathItem := doc.Webhooks.GetOrZero(webhookName) - if pathItem == nil { - continue - } - - // Gather path-level parameters - globalParams, err := g.gatherParameters(pathItem.Parameters) - if err != nil { - return nil, fmt.Errorf("error gathering parameters for webhook %s: %w", webhookName, err) - } - - ops := pathItem.GetOperations() - if ops == nil { - continue - } - - var methods []string - for pair := ops.First(); pair != nil; pair = pair.Next() { - methods = append(methods, pair.Key()) - } - sort.Strings(methods) - - for _, method := range methods { - op := ops.GetOrZero(method) - if op == nil { - continue - } - - // For webhooks, Path is empty (no URL path in the spec) - opDesc, err := g.gatherOperation(method, "", op, globalParams) - if err != nil { - return nil, fmt.Errorf("error gathering webhook operation %s %s: %w", method, webhookName, err) - } - - // Override operation ID if not set - use webhook name + method - if op.OperationId == "" { - opDesc.OperationID = ToCamelCase(method + "-" + webhookName) - opDesc.GoOperationID = ToGoIdentifier(opDesc.OperationID) - opDesc.ParamsTypeName = opDesc.GoOperationID + "Params" - } - - opDesc.Source = OperationSourceWebhook - opDesc.WebhookName = webhookName - - operations = append(operations, opDesc) - } - } - - return operations, nil -} - -func (g *operationGatherer) gatherCallbacks(doc *v3.Document) ([]*OperationDescriptor, error) { - var operations []*OperationDescriptor - - if doc.Paths == nil || doc.Paths.PathItems == nil { - return operations, nil - } - - // Iterate all paths in sorted order - var paths []string - for pair := doc.Paths.PathItems.First(); pair != nil; pair = pair.Next() { - paths = append(paths, pair.Key()) - } - sort.Strings(paths) - - for _, pathStr := range paths { - pathItem := doc.Paths.PathItems.GetOrZero(pathStr) - if pathItem == nil { - continue - } - - pathOps := pathItem.GetOperations() - if pathOps == nil { - continue - } - - var methods []string - for pair := pathOps.First(); pair != nil; pair = pair.Next() { - methods = append(methods, pair.Key()) - } - sort.Strings(methods) - - for _, method := range methods { - parentOp := pathOps.GetOrZero(method) - if parentOp == nil || parentOp.Callbacks == nil || parentOp.Callbacks.Len() == 0 { - continue - } - - parentOpID := parentOp.OperationId - if parentOpID == "" { - parentOpID = generateOperationID(method, pathStr) - } - - // Collect callback names in sorted order - var callbackNames []string - for pair := parentOp.Callbacks.First(); pair != nil; pair = pair.Next() { - callbackNames = append(callbackNames, pair.Key()) - } - sort.Strings(callbackNames) - - for _, callbackName := range callbackNames { - callback := parentOp.Callbacks.GetOrZero(callbackName) - if callback == nil || callback.Expression == nil || callback.Expression.Len() == 0 { - continue - } - - // Iterate callback expressions in sorted order - var expressions []string - for pair := callback.Expression.First(); pair != nil; pair = pair.Next() { - expressions = append(expressions, pair.Key()) - } - sort.Strings(expressions) - - for _, expression := range expressions { - cbPathItem := callback.Expression.GetOrZero(expression) - if cbPathItem == nil { - continue - } - - cbOps := cbPathItem.GetOperations() - if cbOps == nil { - continue - } - - var cbMethods []string - for pair := cbOps.First(); pair != nil; pair = pair.Next() { - cbMethods = append(cbMethods, pair.Key()) - } - sort.Strings(cbMethods) - - for _, cbMethod := range cbMethods { - cbOp := cbOps.GetOrZero(cbMethod) - if cbOp == nil { - continue - } - - // URL expression is stored as path but params are not extracted - // (expressions are runtime-evaluated) - opDesc, err := g.gatherOperation(cbMethod, expression, cbOp, nil) - if err != nil { - return nil, fmt.Errorf("error gathering callback operation %s %s %s: %w", cbMethod, callbackName, expression, err) - } - - // Override operation ID if not set - if cbOp.OperationId == "" { - opDesc.OperationID = ToCamelCase(parentOpID + "-" + callbackName) - opDesc.GoOperationID = ToGoIdentifier(opDesc.OperationID) - opDesc.ParamsTypeName = opDesc.GoOperationID + "Params" - } - - // Clear path params since callback URLs are runtime expressions - opDesc.PathParams = nil - - opDesc.Source = OperationSourceCallback - opDesc.CallbackName = callbackName - opDesc.ParentOpID = parentOpID - - operations = append(operations, opDesc) - } - } - } - } - } - - return operations, nil -} - -// schemaProxyToDescriptor converts a schema proxy to a basic descriptor. -// This is a simplified version - for full type resolution, use the schema gatherer. -func schemaProxyToDescriptor(proxy *base.SchemaProxy) *SchemaDescriptor { - if proxy == nil { - return nil - } - - schema := proxy.Schema() - if schema == nil { - return nil - } - - desc := &SchemaDescriptor{ - Schema: schema, - } - - // Capture reference if this is a reference schema - if proxy.IsReference() { - desc.Ref = proxy.GetReference() - } - - return desc -} - -// schemaToGoType converts a schema to a Go type string. -// This is a simplified version for parameter types. -func schemaToGoType(schema *base.Schema) string { - if schema == nil { - return "interface{}" - } - - // Check for array - if schema.Items != nil && schema.Items.A != nil { - itemType := "interface{}" - if itemSchema := schema.Items.A.Schema(); itemSchema != nil { - itemType = schemaToGoType(itemSchema) - } - return "[]" + itemType - } - - // Check explicit type - for _, t := range schema.Type { - switch t { - case "string": - if schema.Format == "date-time" { - return "time.Time" - } - if schema.Format == "date" { - return "Date" - } - if schema.Format == "uuid" { - return "uuid.UUID" - } - return "string" - case "integer": - if schema.Format == "int64" { - return "int64" - } - if schema.Format == "int32" { - return "int32" - } - return "int" - case "number": - if schema.Format == "float" { - return "float32" - } - return "float64" - case "boolean": - return "bool" - case "array": - // Handled above - return "[]interface{}" - case "object": - return "map[string]interface{}" - } - } - - return "interface{}" -} diff --git a/experimental/internal/codegen/identifiers.go b/experimental/internal/codegen/identifiers.go deleted file mode 100644 index 6a8f58f05b..0000000000 --- a/experimental/internal/codegen/identifiers.go +++ /dev/null @@ -1,125 +0,0 @@ -package codegen - -import ( - "strings" - "unicode" -) - -// Go keywords that can't be used as identifiers -var goKeywords = map[string]bool{ - "break": true, - "case": true, - "chan": true, - "const": true, - "continue": true, - "default": true, - "defer": true, - "else": true, - "fallthrough": true, - "for": true, - "func": true, - "go": true, - "goto": true, - "if": true, - "import": true, - "interface": true, - "map": true, - "package": true, - "range": true, - "return": true, - "select": true, - "struct": true, - "switch": true, - "type": true, - "var": true, -} - -// IsGoKeyword returns true if s is a Go keyword. -func IsGoKeyword(s string) bool { - return goKeywords[s] -} - -// ToCamelCase converts a string to CamelCase (PascalCase). -// It treats hyphens, underscores, spaces, and other non-alphanumeric characters as word separators. -// Example: "user-name" -> "UserName", "user_id" -> "UserId" -func ToCamelCase(s string) string { - if s == "" { - return "" - } - - var result strings.Builder - capitalizeNext := true - - for _, r := range s { - if isWordSeparator(r) { - capitalizeNext = true - continue - } - - if !unicode.IsLetter(r) && !unicode.IsDigit(r) { - capitalizeNext = true - continue - } - - if capitalizeNext { - result.WriteRune(unicode.ToUpper(r)) - capitalizeNext = false - } else { - result.WriteRune(r) - } - } - - return result.String() -} - -// LowercaseFirstCharacter lowercases only the first character of a string. -// Example: "UserName" -> "userName" -func LowercaseFirstCharacter(s string) string { - if s == "" { - return "" - } - runes := []rune(s) - runes[0] = unicode.ToLower(runes[0]) - return string(runes) -} - -// UppercaseFirstCharacter uppercases only the first character of a string. -// Example: "userName" -> "UserName" -func UppercaseFirstCharacter(s string) string { - if s == "" { - return "" - } - runes := []rune(s) - runes[0] = unicode.ToUpper(runes[0]) - return string(runes) -} - -// isWordSeparator returns true if the rune is a word separator. -func isWordSeparator(r rune) bool { - return r == '-' || r == '_' || r == ' ' || r == '.' || r == '/' -} - -// ToGoIdentifier converts a string to a valid Go identifier. -// It converts to CamelCase, handles leading digits, and avoids Go keywords. -func ToGoIdentifier(s string) string { - result := ToCamelCase(s) - - // Handle empty result - if result == "" { - return "Empty" - } - - // Handle leading digits - if result[0] >= '0' && result[0] <= '9' { - result = "N" + result - } - - // Handle Go keywords - check both the original input and lowercase result - // "type" -> "Type" but we still want to avoid "Type" being used as-is - // since user might write it as lowercase in code - if IsGoKeyword(s) || IsGoKeyword(strings.ToLower(result)) { - result = result + "_" - } - - return result -} diff --git a/experimental/internal/codegen/identifiers_test.go b/experimental/internal/codegen/identifiers_test.go deleted file mode 100644 index 4d5eca6328..0000000000 --- a/experimental/internal/codegen/identifiers_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestIsGoKeyword(t *testing.T) { - keywords := []string{ - "break", "case", "chan", "const", "continue", - "default", "defer", "else", "fallthrough", "for", - "func", "go", "goto", "if", "import", - "interface", "map", "package", "range", "return", - "select", "struct", "switch", "type", "var", - } - - for _, kw := range keywords { - t.Run(kw, func(t *testing.T) { - assert.True(t, IsGoKeyword(kw), "%s should be a keyword", kw) - }) - } - - nonKeywords := []string{ - "user", "name", "id", "Type", "Interface", "Map", - "string", "int", "bool", "error", // predeclared but not keywords - } - - for _, nkw := range nonKeywords { - t.Run(nkw+"_not_keyword", func(t *testing.T) { - assert.False(t, IsGoKeyword(nkw), "%s should not be a keyword", nkw) - }) - } -} - -func TestToCamelCase(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {"", ""}, - {"user", "User"}, - {"user_name", "UserName"}, - {"user-name", "UserName"}, - {"user.name", "UserName"}, - {"user name", "UserName"}, - {"USER", "USER"}, - {"USER_NAME", "USERNAME"}, - {"123", "123"}, - {"user123", "User123"}, - {"user123name", "User123name"}, - {"get-users-by-id", "GetUsersById"}, - {"__private", "Private"}, - {"a_b_c", "ABC"}, - {"already_CamelCase", "AlreadyCamelCase"}, - {"path/to/resource", "PathToResource"}, - } - - for _, tc := range tests { - t.Run(tc.input, func(t *testing.T) { - result := ToCamelCase(tc.input) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestLowercaseFirstCharacter(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {"", ""}, - {"User", "user"}, - {"UserName", "userName"}, - {"user", "user"}, - {"ABC", "aBC"}, - {"123", "123"}, - } - - for _, tc := range tests { - t.Run(tc.input, func(t *testing.T) { - result := LowercaseFirstCharacter(tc.input) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestUppercaseFirstCharacter(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {"", ""}, - {"user", "User"}, - {"userName", "UserName"}, - {"User", "User"}, - {"abc", "Abc"}, - } - - for _, tc := range tests { - t.Run(tc.input, func(t *testing.T) { - result := UppercaseFirstCharacter(tc.input) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestToGoIdentifier(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {"user", "User"}, - {"user_name", "UserName"}, - {"123abc", "N123abc"}, - {"type", "Type_"}, - {"map", "Map_"}, - {"interface", "Interface_"}, - {"", "Empty"}, - {"get-users", "GetUsers"}, - } - - for _, tc := range tests { - t.Run(tc.input, func(t *testing.T) { - result := ToGoIdentifier(tc.input) - assert.Equal(t, tc.expected, result) - }) - } -} diff --git a/experimental/internal/codegen/initiatorgen.go b/experimental/internal/codegen/initiatorgen.go deleted file mode 100644 index 67a9aa08fa..0000000000 --- a/experimental/internal/codegen/initiatorgen.go +++ /dev/null @@ -1,216 +0,0 @@ -package codegen - -import ( - "bytes" - "fmt" - "strings" - "text/template" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// InitiatorTemplateData is passed to initiator templates. -type InitiatorTemplateData struct { - Prefix string // "Webhook" or "Callback" - PrefixLower string // "webhook" or "callback" - Operations []*OperationDescriptor // Operations to generate for -} - -// InitiatorGenerator generates initiator (sender) code from operation descriptors. -// It is parameterized by prefix to support both webhooks and callbacks. -type InitiatorGenerator struct { - tmpl *template.Template - prefix string // "Webhook" or "Callback" - schemaIndex map[string]*SchemaDescriptor - generateSimple bool - modelsPackage *ModelsPackage -} - -// NewInitiatorGenerator creates a new initiator generator. -func NewInitiatorGenerator(prefix string, schemaIndex map[string]*SchemaDescriptor, generateSimple bool, modelsPackage *ModelsPackage) (*InitiatorGenerator, error) { - tmpl := template.New("initiator").Funcs(templates.Funcs()).Funcs(clientFuncs(schemaIndex, modelsPackage)) - - // Parse initiator templates - for _, pt := range templates.InitiatorTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + pt.Template) - if err != nil { - return nil, fmt.Errorf("failed to read initiator template %s: %w", pt.Template, err) - } - _, err = tmpl.New(pt.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse initiator template %s: %w", pt.Template, err) - } - } - - // Parse shared templates (param_types) - for _, st := range templates.SharedServerTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + st.Template) - if err != nil { - return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) - } - _, err = tmpl.New(st.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) - } - } - - return &InitiatorGenerator{ - tmpl: tmpl, - prefix: prefix, - schemaIndex: schemaIndex, - generateSimple: generateSimple, - modelsPackage: modelsPackage, - }, nil -} - -func (g *InitiatorGenerator) templateData(ops []*OperationDescriptor) InitiatorTemplateData { - return InitiatorTemplateData{ - Prefix: g.prefix, - PrefixLower: strings.ToLower(g.prefix), - Operations: ops, - } -} - -// GenerateBase generates the base initiator types and helpers. -func (g *InitiatorGenerator) GenerateBase(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "initiator_base", g.templateData(ops)); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateInterface generates the InitiatorInterface. -func (g *InitiatorGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "initiator_interface", g.templateData(ops)); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateMethods generates the Initiator methods. -func (g *InitiatorGenerator) GenerateMethods(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "initiator_methods", g.templateData(ops)); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateRequestBuilders generates the request builder functions. -func (g *InitiatorGenerator) GenerateRequestBuilders(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "initiator_request_builders", g.templateData(ops)); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateSimple generates the SimpleInitiator with typed responses. -func (g *InitiatorGenerator) GenerateSimple(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "initiator_simple", g.templateData(ops)); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateParamTypes generates the parameter struct types. -func (g *InitiatorGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateRequestBodyTypes generates type aliases for request bodies. -func (g *InitiatorGenerator) GenerateRequestBodyTypes(ops []*OperationDescriptor) string { - var buf bytes.Buffer - pkgPrefix := g.modelsPackage.Prefix() - - for _, op := range ops { - for _, body := range op.Bodies { - if !body.IsJSON { - continue - } - var targetType string - if body.Schema != nil { - if body.Schema.Ref != "" { - if target, ok := g.schemaIndex[body.Schema.Ref]; ok { - targetType = pkgPrefix + target.ShortName - } - } else if body.Schema.ShortName != "" { - targetType = pkgPrefix + body.Schema.ShortName - } - } - if targetType == "" { - targetType = "interface{}" - } - buf.WriteString(fmt.Sprintf("type %s = %s\n\n", body.GoTypeName, targetType)) - } - } - - return buf.String() -} - -// GenerateInitiator generates the complete initiator code. -func (g *InitiatorGenerator) GenerateInitiator(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - - // Generate request body type aliases first - bodyTypes := g.GenerateRequestBodyTypes(ops) - buf.WriteString(bodyTypes) - - // Generate base initiator - base, err := g.GenerateBase(ops) - if err != nil { - return "", fmt.Errorf("generating base initiator: %w", err) - } - buf.WriteString(base) - buf.WriteString("\n") - - // Generate interface - iface, err := g.GenerateInterface(ops) - if err != nil { - return "", fmt.Errorf("generating initiator interface: %w", err) - } - buf.WriteString(iface) - buf.WriteString("\n") - - // Generate param types - paramTypes, err := g.GenerateParamTypes(ops) - if err != nil { - return "", fmt.Errorf("generating param types: %w", err) - } - buf.WriteString(paramTypes) - buf.WriteString("\n") - - // Generate methods - methods, err := g.GenerateMethods(ops) - if err != nil { - return "", fmt.Errorf("generating initiator methods: %w", err) - } - buf.WriteString(methods) - buf.WriteString("\n") - - // Generate request builders - builders, err := g.GenerateRequestBuilders(ops) - if err != nil { - return "", fmt.Errorf("generating request builders: %w", err) - } - buf.WriteString(builders) - buf.WriteString("\n") - - // Generate simple initiator if requested - if g.generateSimple { - simple, err := g.GenerateSimple(ops) - if err != nil { - return "", fmt.Errorf("generating simple initiator: %w", err) - } - buf.WriteString(simple) - } - - return buf.String(), nil -} diff --git a/experimental/internal/codegen/inline.go b/experimental/internal/codegen/inline.go deleted file mode 100644 index 25767cffa8..0000000000 --- a/experimental/internal/codegen/inline.go +++ /dev/null @@ -1,92 +0,0 @@ -package codegen - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" -) - -// generateEmbeddedSpec produces Go code that embeds the raw OpenAPI spec as -// gzip+base64 encoded data, with a public GetSwaggerSpecJSON() function to -// retrieve the decompressed JSON bytes. -func generateEmbeddedSpec(specData []byte) (string, error) { - // Gzip compress - var buf bytes.Buffer - gz, err := gzip.NewWriterLevel(&buf, gzip.BestCompression) - if err != nil { - return "", fmt.Errorf("creating gzip writer: %w", err) - } - if _, err := gz.Write(specData); err != nil { - return "", fmt.Errorf("gzip writing: %w", err) - } - if err := gz.Close(); err != nil { - return "", fmt.Errorf("gzip close: %w", err) - } - - // Base64 encode - encoded := base64.StdEncoding.EncodeToString(buf.Bytes()) - - // Split into 80-char chunks - var chunks []string - for len(encoded) > 0 { - end := 80 - if end > len(encoded) { - end = len(encoded) - } - chunks = append(chunks, encoded[:end]) - encoded = encoded[end:] - } - - // Build Go code - var b strings.Builder - - b.WriteString("// Base64-encoded, gzip-compressed OpenAPI spec.\n") - b.WriteString("var swaggerSpecJSON = []string{\n") - for _, chunk := range chunks { - fmt.Fprintf(&b, "\t%q,\n", chunk) - } - b.WriteString("}\n\n") - - b.WriteString("// decodeSwaggerSpec decodes and decompresses the embedded spec.\n") - b.WriteString("func decodeSwaggerSpec() ([]byte, error) {\n") - b.WriteString("\tjoined := strings.Join(swaggerSpecJSON, \"\")\n") - b.WriteString("\traw, err := base64.StdEncoding.DecodeString(joined)\n") - b.WriteString("\tif err != nil {\n") - b.WriteString("\t\treturn nil, fmt.Errorf(\"decoding base64: %w\", err)\n") - b.WriteString("\t}\n") - b.WriteString("\tr, err := gzip.NewReader(bytes.NewReader(raw))\n") - b.WriteString("\tif err != nil {\n") - b.WriteString("\t\treturn nil, fmt.Errorf(\"creating gzip reader: %w\", err)\n") - b.WriteString("\t}\n") - b.WriteString("\tdefer r.Close()\n") - b.WriteString("\tvar out bytes.Buffer\n") - b.WriteString("\tif _, err := out.ReadFrom(r); err != nil {\n") - b.WriteString("\t\treturn nil, fmt.Errorf(\"decompressing: %w\", err)\n") - b.WriteString("\t}\n") - b.WriteString("\treturn out.Bytes(), nil\n") - b.WriteString("}\n\n") - - b.WriteString("// decodeSwaggerSpecCached returns a closure that caches the decoded spec.\n") - b.WriteString("func decodeSwaggerSpecCached() func() ([]byte, error) {\n") - b.WriteString("\tvar cached []byte\n") - b.WriteString("\tvar cachedErr error\n") - b.WriteString("\tvar once sync.Once\n") - b.WriteString("\treturn func() ([]byte, error) {\n") - b.WriteString("\t\tonce.Do(func() {\n") - b.WriteString("\t\t\tcached, cachedErr = decodeSwaggerSpec()\n") - b.WriteString("\t\t})\n") - b.WriteString("\t\treturn cached, cachedErr\n") - b.WriteString("\t}\n") - b.WriteString("}\n\n") - - b.WriteString("var swaggerSpec = decodeSwaggerSpecCached()\n\n") - - b.WriteString("// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes.\n") - b.WriteString("func GetSwaggerSpecJSON() ([]byte, error) {\n") - b.WriteString("\treturn swaggerSpec()\n") - b.WriteString("}\n") - - return b.String(), nil -} diff --git a/experimental/internal/codegen/inline_test.go b/experimental/internal/codegen/inline_test.go deleted file mode 100644 index ae35938493..0000000000 --- a/experimental/internal/codegen/inline_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package codegen - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "strings" - "testing" - - "github.com/pb33f/libopenapi" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGenerateEmbeddedSpec(t *testing.T) { - specData := []byte(`{"openapi":"3.0.0","info":{"title":"Test","version":"1.0"}}`) - - code, err := generateEmbeddedSpec(specData) - require.NoError(t, err) - - // Should contain the chunked base64 variable - assert.Contains(t, code, "var swaggerSpecJSON = []string{") - - // Should contain the decode function - assert.Contains(t, code, "func decodeSwaggerSpec() ([]byte, error)") - - // Should contain the cached decode function - assert.Contains(t, code, "func decodeSwaggerSpecCached() func() ([]byte, error)") - - // Should contain the public API - assert.Contains(t, code, "func GetSwaggerSpecJSON() ([]byte, error)") - - // Should contain the cached var - assert.Contains(t, code, "var swaggerSpec = decodeSwaggerSpecCached()") -} - -func TestGenerateEmbeddedSpecRoundTrip(t *testing.T) { - specData := []byte(`{"openapi":"3.0.0","info":{"title":"Test API","version":"1.0"},"paths":{}}`) - - code, err := generateEmbeddedSpec(specData) - require.NoError(t, err) - - // Extract the base64 chunks from the generated code - var chunks []string - for _, line := range strings.Split(code, "\n") { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, `"`) && strings.HasSuffix(line, `",`) { - // Remove quotes and trailing comma - chunk := line[1 : len(line)-2] - chunks = append(chunks, chunk) - } - } - require.NotEmpty(t, chunks, "should have extracted base64 chunks") - - // Decode base64 - joined := strings.Join(chunks, "") - raw, err := base64.StdEncoding.DecodeString(joined) - require.NoError(t, err) - - // Decompress gzip - r, err := gzip.NewReader(bytes.NewReader(raw)) - require.NoError(t, err) - defer func() { _ = r.Close() }() - - var out bytes.Buffer - _, err = out.ReadFrom(r) - require.NoError(t, err) - - // Should match original spec - assert.Equal(t, specData, out.Bytes()) -} - -func TestGenerateEmbeddedSpecInGenerate(t *testing.T) { - spec := `openapi: "3.0.0" -info: - title: Test API - version: "1.0" -paths: {} -components: - schemas: - Pet: - type: object - properties: - name: - type: string -` - - specBytes := []byte(spec) - - doc, err := libopenapi.NewDocument(specBytes) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - } - - code, err := Generate(doc, specBytes, cfg) - require.NoError(t, err) - - // Should contain the model type - assert.Contains(t, code, "type Pet struct") - - // Should contain the embedded spec - assert.Contains(t, code, "GetSwaggerSpecJSON") - assert.Contains(t, code, "swaggerSpecJSON") -} - -func TestGenerateWithNilSpecData(t *testing.T) { - spec := `openapi: "3.0.0" -info: - title: Test API - version: "1.0" -paths: {} -components: - schemas: - Pet: - type: object - properties: - name: - type: string -` - - doc, err := libopenapi.NewDocument([]byte(spec)) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "testpkg", - } - - code, err := Generate(doc, nil, cfg) - require.NoError(t, err) - - // Should contain the model type - assert.Contains(t, code, "type Pet struct") - - // Should NOT contain the embedded spec - assert.NotContains(t, code, "GetSwaggerSpecJSON") - assert.NotContains(t, code, "swaggerSpecJSON") -} diff --git a/experimental/internal/codegen/namemangling.go b/experimental/internal/codegen/namemangling.go deleted file mode 100644 index 9dff27a642..0000000000 --- a/experimental/internal/codegen/namemangling.go +++ /dev/null @@ -1,420 +0,0 @@ -package codegen - -import ( - "strings" - "unicode" -) - -// NameMangling configures how OpenAPI names are converted to valid Go identifiers. -type NameMangling struct { - // CharacterSubstitutions maps characters to their word replacements. - // Used when these characters appear at the start of a name. - // Example: '$' -> "DollarSign", '-' -> "Minus" - CharacterSubstitutions map[string]string `yaml:"character-substitutions,omitempty"` - - // WordSeparators is a string of characters that mark word boundaries. - // When encountered, the next letter is capitalized. - // Example: "-_. " means "foo-bar" becomes "FooBar" - WordSeparators string `yaml:"word-separators,omitempty"` - - // NumericPrefix is prepended when a name starts with a digit. - // Example: "N" means "123foo" becomes "N123foo" - NumericPrefix string `yaml:"numeric-prefix,omitempty"` - - // KeywordPrefix is prepended when a name conflicts with a Go keyword. - // Example: "_" means "type" becomes "_type" - KeywordPrefix string `yaml:"keyword-prefix,omitempty"` - - // Initialisms is a list of words that should be all-uppercase. - // Example: ["ID", "HTTP", "URL"] means "userId" becomes "UserID" - Initialisms []string `yaml:"initialisms,omitempty"` -} - -// DefaultNameMangling returns sensible defaults for name mangling. -func DefaultNameMangling() NameMangling { - return NameMangling{ - CharacterSubstitutions: map[string]string{ - "$": "DollarSign", - "-": "Minus", - "+": "Plus", - "&": "And", - "|": "Or", - "~": "Tilde", - "=": "Equal", - ">": "GreaterThan", - "<": "LessThan", - "#": "Hash", - ".": "Dot", - "*": "Asterisk", - "^": "Caret", - "%": "Percent", - "_": "Underscore", - "@": "At", - "!": "Bang", - "?": "Question", - "/": "Slash", - "\\": "Backslash", - ":": "Colon", - ";": "Semicolon", - "'": "Apos", - "\"": "Quote", - "`": "Backtick", - "(": "LParen", - ")": "RParen", - "[": "LBracket", - "]": "RBracket", - "{": "LBrace", - "}": "RBrace", - }, - WordSeparators: "-#@!$&=.+:;_~ (){}[]|<>?/\\", - NumericPrefix: "N", - KeywordPrefix: "_", - Initialisms: []string{ - "ACL", "API", "ASCII", "CPU", "CSS", "DB", "DNS", "EOF", - "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", - "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", - "TLS", "TTL", "UDP", "UI", "UID", "GID", "URI", "URL", - "UTF8", "UUID", "VM", "XML", "XMPP", "XSRF", "XSS", - "SIP", "RTP", "AMQP", "TS", - }, - } -} - -// Merge returns a new NameMangling with user values overlaid on defaults. -// Non-zero user values override defaults. -func (n NameMangling) Merge(user NameMangling) NameMangling { - result := n - - // Merge character substitutions (user overrides/adds to defaults) - if len(user.CharacterSubstitutions) > 0 { - merged := make(map[string]string, len(n.CharacterSubstitutions)) - for k, v := range n.CharacterSubstitutions { - merged[k] = v - } - for k, v := range user.CharacterSubstitutions { - if v == "" { - // Empty string means "remove this substitution" - delete(merged, k) - } else { - merged[k] = v - } - } - result.CharacterSubstitutions = merged - } - - if user.WordSeparators != "" { - result.WordSeparators = user.WordSeparators - } - if user.NumericPrefix != "" { - result.NumericPrefix = user.NumericPrefix - } - if user.KeywordPrefix != "" { - result.KeywordPrefix = user.KeywordPrefix - } - if len(user.Initialisms) > 0 { - result.Initialisms = user.Initialisms - } - - return result -} - -// NameSubstitutions holds direct name overrides for generated identifiers. -type NameSubstitutions struct { - // TypeNames maps generated type names to user-preferred names. - // Example: {"MyGeneratedType": "MyPreferredName"} - TypeNames map[string]string `yaml:"type-names,omitempty"` - - // PropertyNames maps generated property/field names to user-preferred names. - // Example: {"GeneratedField": "PreferredField"} - PropertyNames map[string]string `yaml:"property-names,omitempty"` -} - -// NameConverter handles converting OpenAPI names to Go identifiers. -type NameConverter struct { - mangling NameMangling - substitutions NameSubstitutions - initialismSet map[string]bool -} - -// NewNameConverter creates a NameConverter with the given configuration. -func NewNameConverter(mangling NameMangling, substitutions NameSubstitutions) *NameConverter { - initialismSet := make(map[string]bool, len(mangling.Initialisms)) - for _, init := range mangling.Initialisms { - initialismSet[strings.ToUpper(init)] = true - } - return &NameConverter{ - mangling: mangling, - substitutions: substitutions, - initialismSet: initialismSet, - } -} - -// ToTypeName converts an OpenAPI schema name to a Go type name. -func (c *NameConverter) ToTypeName(name string) string { - // Check for direct substitution first - if sub, ok := c.substitutions.TypeNames[name]; ok { - return sub - } - return c.toGoIdentifier(name, true) -} - -// ToTypeNamePart converts a name to a type name component that will be joined with others. -// Unlike ToTypeName, it doesn't add a numeric prefix since the result won't be the start of an identifier. -func (c *NameConverter) ToTypeNamePart(name string) string { - // Check for direct substitution first - if sub, ok := c.substitutions.TypeNames[name]; ok { - return sub - } - return c.toGoIdentifierPart(name) -} - -// ToPropertyName converts an OpenAPI property name to a Go field name. -func (c *NameConverter) ToPropertyName(name string) string { - // Check for direct substitution first - if sub, ok := c.substitutions.PropertyNames[name]; ok { - return sub - } - return c.toGoIdentifier(name, true) -} - -// ToVariableName converts an OpenAPI name to a Go variable name (unexported). -func (c *NameConverter) ToVariableName(name string) string { - id := c.toGoIdentifier(name, false) - if id == "" { - return id - } - // Make first letter lowercase - runes := []rune(id) - runes[0] = unicode.ToLower(runes[0]) - return string(runes) -} - -// toGoIdentifier converts a name to a valid Go identifier. -func (c *NameConverter) toGoIdentifier(name string, exported bool) string { - if name == "" { - return "Empty" - } - - // Build the identifier with prefix handling - var result strings.Builder - prefix := c.getPrefix(name) - result.WriteString(prefix) - - // Convert the rest using word boundaries - capitalizeNext := exported || prefix != "" - prevWasDigit := false - for _, r := range name { - if c.isWordSeparator(r) { - capitalizeNext = true - prevWasDigit = false - continue - } - - if !unicode.IsLetter(r) && !unicode.IsDigit(r) { - // Skip invalid characters (already handled by prefix if at start) - capitalizeNext = true - prevWasDigit = false - continue - } - - // Capitalize after digits - if prevWasDigit && unicode.IsLetter(r) { - capitalizeNext = true - } - - if capitalizeNext && unicode.IsLetter(r) { - result.WriteRune(unicode.ToUpper(r)) - capitalizeNext = false - } else { - result.WriteRune(r) - } - - prevWasDigit = unicode.IsDigit(r) - } - - id := result.String() - if id == "" { - return "Empty" - } - - // Apply initialism fixes - id = c.applyInitialisms(id) - - return id -} - -// toGoIdentifierPart converts a name to a Go identifier component (for joining with others). -// It doesn't add a numeric prefix since the result won't necessarily be at the start of an identifier. -func (c *NameConverter) toGoIdentifierPart(name string) string { - if name == "" { - return "" - } - - // Build the identifier without numeric prefix (but still handle special characters at start) - var result strings.Builder - - // Only add prefix for non-digit special characters at the start - firstRune := []rune(name)[0] - if !unicode.IsLetter(firstRune) && !unicode.IsDigit(firstRune) { - firstChar := string(firstRune) - if sub, ok := c.mangling.CharacterSubstitutions[firstChar]; ok { - result.WriteString(sub) - } else { - result.WriteString("X") - } - } - - // Convert the rest using word boundaries (always capitalize since this is a part) - capitalizeNext := true - prevWasDigit := false - for _, r := range name { - if c.isWordSeparator(r) { - capitalizeNext = true - prevWasDigit = false - continue - } - - if !unicode.IsLetter(r) && !unicode.IsDigit(r) { - // Skip invalid characters (already handled by prefix if at start) - capitalizeNext = true - prevWasDigit = false - continue - } - - // Capitalize after digits - if prevWasDigit && unicode.IsLetter(r) { - capitalizeNext = true - } - - if capitalizeNext && unicode.IsLetter(r) { - result.WriteRune(unicode.ToUpper(r)) - capitalizeNext = false - } else { - result.WriteRune(r) - } - - prevWasDigit = unicode.IsDigit(r) - } - - id := result.String() - - // Apply initialism fixes - id = c.applyInitialisms(id) - - return id -} - -// getPrefix returns the prefix needed for names starting with invalid characters. -func (c *NameConverter) getPrefix(name string) string { - if name == "" { - return "" - } - - firstRune := []rune(name)[0] - - // Check if starts with digit - if unicode.IsDigit(firstRune) { - return c.mangling.NumericPrefix - } - - // Check if starts with letter (valid, no prefix needed) - if unicode.IsLetter(firstRune) { - return "" - } - - // Check character substitutions - firstChar := string(firstRune) - if sub, ok := c.mangling.CharacterSubstitutions[firstChar]; ok { - return sub - } - - // Unknown special character, use generic prefix - return "X" -} - -// isWordSeparator returns true if the rune is a word separator. -func (c *NameConverter) isWordSeparator(r rune) bool { - return strings.ContainsRune(c.mangling.WordSeparators, r) -} - -// applyInitialisms uppercases known initialisms in the identifier. -// It detects initialisms at word boundaries in PascalCase identifiers. -func (c *NameConverter) applyInitialisms(name string) string { - if len(name) == 0 { - return name - } - - // Split the identifier into "words" based on case transitions - // e.g., "UserId" -> ["User", "Id"], "HTTPUrl" -> ["HTTP", "Url"] - words := splitPascalCase(name) - - // Check each word against initialisms - for i, word := range words { - upper := strings.ToUpper(word) - if c.initialismSet[upper] { - words[i] = upper - } - } - - return strings.Join(words, "") -} - -// splitPascalCase splits a PascalCase identifier into words. -// e.g., "UserId" -> ["User", "Id"], "HTTPServer" -> ["HTTP", "Server"] -func splitPascalCase(s string) []string { - if len(s) == 0 { - return nil - } - - var words []string - var currentWord strings.Builder - - runes := []rune(s) - for i := 0; i < len(runes); i++ { - r := runes[i] - - if i == 0 { - currentWord.WriteRune(r) - continue - } - - prevUpper := unicode.IsUpper(runes[i-1]) - currUpper := unicode.IsUpper(r) - currDigit := unicode.IsDigit(r) - - // Start new word on: - // 1. Lowercase to uppercase transition (e.g., "userId" -> "user" | "Id") - // 2. Multiple uppercase followed by lowercase (e.g., "HTTPServer" -> "HTTP" | "Server") - if currUpper && !prevUpper { - // Lowercase to uppercase: start new word - words = append(words, currentWord.String()) - currentWord.Reset() - currentWord.WriteRune(r) - } else if currUpper && prevUpper && i+1 < len(runes) && unicode.IsLower(runes[i+1]) { - // Uppercase followed by lowercase, and previous was uppercase - // This is the start of a new word after an acronym - // e.g., in "HTTPServer", 'S' starts a new word - words = append(words, currentWord.String()) - currentWord.Reset() - currentWord.WriteRune(r) - } else if currDigit && !unicode.IsDigit(runes[i-1]) { - // Transition to digit: start new word - words = append(words, currentWord.String()) - currentWord.Reset() - currentWord.WriteRune(r) - } else if !currDigit && unicode.IsDigit(runes[i-1]) { - // Transition from digit: start new word - words = append(words, currentWord.String()) - currentWord.Reset() - currentWord.WriteRune(r) - } else { - currentWord.WriteRune(r) - } - } - - if currentWord.Len() > 0 { - words = append(words, currentWord.String()) - } - - return words -} diff --git a/experimental/internal/codegen/namemangling_test.go b/experimental/internal/codegen/namemangling_test.go deleted file mode 100644 index 6d36cc0749..0000000000 --- a/experimental/internal/codegen/namemangling_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestToTypeName(t *testing.T) { - c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) - - tests := []struct { - input string - expected string - }{ - // Basic conversions - {"foo", "Foo"}, - {"fooBar", "FooBar"}, - {"foo_bar", "FooBar"}, - {"foo-bar", "FooBar"}, - {"foo.bar", "FooBar"}, - - // Names starting with numbers - {"123", "N123"}, - {"123foo", "N123Foo"}, - {"1param", "N1Param"}, - - // Names starting with special characters - {"$ref", "DollarSignRef"}, - {"$", "DollarSign"}, - {"-1", "Minus1"}, - {"+1", "Plus1"}, - {"&now", "AndNow"}, - {"#tag", "HashTag"}, - {".hidden", "DotHidden"}, - {"@timestamp", "AtTimestamp"}, - {"_private", "UnderscorePrivate"}, - - // Initialisms - {"userId", "UserID"}, - {"httpUrl", "HTTPURL"}, - {"apiId", "APIID"}, - {"jsonData", "JSONData"}, - {"xmlParser", "XMLParser"}, - {"getHttpResponse", "GetHTTPResponse"}, - - // Go keywords - PascalCase doesn't conflict with lowercase keywords - {"type", "Type"}, - {"interface", "Interface"}, - {"map", "Map"}, - {"chan", "Chan"}, - - // Predeclared identifiers - PascalCase doesn't conflict with lowercase identifiers - {"string", "String"}, - {"int", "Int"}, - {"error", "Error"}, - {"nil", "Nil"}, - - // Edge cases - {"", "Empty"}, - {"a", "A"}, - {"A", "A"}, - {"ABC", "ABC"}, - {"myXMLParser", "MyXMLParser"}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - result := c.ToTypeName(tt.input) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestToPropertyName(t *testing.T) { - c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) - - tests := []struct { - input string - expected string - }{ - {"user_id", "UserID"}, - {"created_at", "CreatedAt"}, - {"is_active", "IsActive"}, - {"123field", "N123Field"}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - result := c.ToPropertyName(tt.input) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestToVariableName(t *testing.T) { - c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{}) - - tests := []struct { - input string - expected string - }{ - {"Foo", "foo"}, - {"FooBar", "fooBar"}, - {"user_id", "userID"}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - result := c.ToVariableName(tt.input) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestNameSubstitutions(t *testing.T) { - c := NewNameConverter(DefaultNameMangling(), NameSubstitutions{ - TypeNames: map[string]string{ - "foo": "MyCustomFoo", - }, - PropertyNames: map[string]string{ - "bar": "MyCustomBar", - }, - }) - - assert.Equal(t, "MyCustomFoo", c.ToTypeName("foo")) - assert.Equal(t, "MyCustomBar", c.ToPropertyName("bar")) - - // Non-substituted names still work normally - assert.Equal(t, "Baz", c.ToTypeName("baz")) -} - -func TestCustomNameMangling(t *testing.T) { - // Custom config that changes numeric prefix - mangling := DefaultNameMangling() - mangling.NumericPrefix = "Num" - - c := NewNameConverter(mangling, NameSubstitutions{}) - - assert.Equal(t, "Num123", c.ToTypeName("123")) - assert.Equal(t, "Num1Foo", c.ToTypeName("1foo")) -} - -func TestMergeNameMangling(t *testing.T) { - defaults := DefaultNameMangling() - - // User wants to change just the numeric prefix - user := NameMangling{ - NumericPrefix: "Number", - } - - merged := defaults.Merge(user) - - // User value overrides - assert.Equal(t, "Number", merged.NumericPrefix) - - // Defaults preserved - assert.Equal(t, defaults.KeywordPrefix, merged.KeywordPrefix) - assert.Equal(t, defaults.WordSeparators, merged.WordSeparators) - assert.Equal(t, len(defaults.CharacterSubstitutions), len(merged.CharacterSubstitutions)) -} - -func TestMergeCharacterSubstitutions(t *testing.T) { - defaults := DefaultNameMangling() - - // User wants to override $ and add a new one - user := NameMangling{ - CharacterSubstitutions: map[string]string{ - "$": "Dollar", // Override default "DollarSign" - "€": "Euro", // Add new - }, - } - - merged := defaults.Merge(user) - - assert.Equal(t, "Dollar", merged.CharacterSubstitutions["$"]) - assert.Equal(t, "Euro", merged.CharacterSubstitutions["€"]) - assert.Equal(t, "Minus", merged.CharacterSubstitutions["-"]) // Default preserved -} - -func TestRemoveCharacterSubstitution(t *testing.T) { - defaults := DefaultNameMangling() - - // User wants to remove $ substitution (empty string = remove) - user := NameMangling{ - CharacterSubstitutions: map[string]string{ - "$": "", // Remove - }, - } - - merged := defaults.Merge(user) - - _, exists := merged.CharacterSubstitutions["$"] - assert.False(t, exists) -} diff --git a/experimental/internal/codegen/operation.go b/experimental/internal/codegen/operation.go deleted file mode 100644 index 88cb4fe27a..0000000000 --- a/experimental/internal/codegen/operation.go +++ /dev/null @@ -1,287 +0,0 @@ -package codegen - -import ( - "strings" - - v3 "github.com/pb33f/libopenapi/datamodel/high/v3" -) - -// OperationSource indicates where an operation was defined in the spec. -type OperationSource string - -const ( - OperationSourcePath OperationSource = "path" - OperationSourceWebhook OperationSource = "webhook" - OperationSourceCallback OperationSource = "callback" -) - -// OperationDescriptor describes a single API operation from an OpenAPI spec. -type OperationDescriptor struct { - OperationID string // Normalized operation ID for function names - GoOperationID string // Go-safe identifier (handles leading digits, keywords) - Method string // HTTP method: GET, POST, PUT, DELETE, etc. - Path string // Original path: /users/{id} - Summary string // For generating comments - Description string // Longer description - - // Source indicates where this operation was defined (path, webhook, or callback) - Source OperationSource - WebhookName string // Webhook name (for Source=webhook) - CallbackName string // Callback key (for Source=callback) - ParentOpID string // Parent operation ID (for Source=callback) - - PathParams []*ParameterDescriptor - QueryParams []*ParameterDescriptor - HeaderParams []*ParameterDescriptor - CookieParams []*ParameterDescriptor - - Bodies []*RequestBodyDescriptor - Responses []*ResponseDescriptor - - Security []SecurityRequirement - - // Precomputed for templates - HasBody bool // Has at least one request body - HasParams bool // Has non-path params (needs Params struct) - ParamsTypeName string // "{OperationID}Params" - - // Reference to the underlying spec - Spec *v3.Operation -} - -// Params returns all non-path parameters (query, header, cookie). -// These are bundled into a Params struct. -func (o *OperationDescriptor) Params() []*ParameterDescriptor { - result := make([]*ParameterDescriptor, 0, len(o.QueryParams)+len(o.HeaderParams)+len(o.CookieParams)) - result = append(result, o.QueryParams...) - result = append(result, o.HeaderParams...) - result = append(result, o.CookieParams...) - return result -} - -// AllParams returns all parameters including path params. -func (o *OperationDescriptor) AllParams() []*ParameterDescriptor { - result := make([]*ParameterDescriptor, 0, len(o.PathParams)+len(o.QueryParams)+len(o.HeaderParams)+len(o.CookieParams)) - result = append(result, o.PathParams...) - result = append(result, o.QueryParams...) - result = append(result, o.HeaderParams...) - result = append(result, o.CookieParams...) - return result -} - -// SummaryAsComment returns the summary formatted as a Go comment. -func (o *OperationDescriptor) SummaryAsComment() string { - if o.Summary == "" { - return "" - } - trimmed := strings.TrimSuffix(o.Summary, "\n") - parts := strings.Split(trimmed, "\n") - for i, p := range parts { - parts[i] = "// " + p - } - return strings.Join(parts, "\n") -} - -// DefaultBody returns the default request body (typically application/json), or nil. -func (o *OperationDescriptor) DefaultBody() *RequestBodyDescriptor { - for _, b := range o.Bodies { - if b.IsDefault { - return b - } - } - if len(o.Bodies) > 0 { - return o.Bodies[0] - } - return nil -} - -// ParameterDescriptor describes a parameter in any location. -type ParameterDescriptor struct { - Name string // Original name from spec (e.g., "user_id") - GoName string // Go-safe name for struct fields (e.g., "UserId") - Location string // "path", "query", "header", "cookie" - Required bool - - // Serialization style - Style string // "simple", "form", "label", "matrix", etc. - Explode bool - - // Type information - Schema *SchemaDescriptor - TypeDecl string // Go type declaration (e.g., "string", "[]int", "*MyType") - - // Precomputed function names for templates - StyleFunc string // "StyleSimpleParam", "StyleFormExplodeParam", etc. - BindFunc string // "BindSimpleParam", "BindFormExplodeParam", etc. - - // Encoding modes - IsStyled bool // Uses style/explode serialization (most common) - IsPassThrough bool // No styling, just pass the string through - IsJSON bool // Parameter uses JSON content encoding - - Spec *v3.Parameter -} - -// GoVariableName returns a Go-safe variable name for this parameter. -// Used for local variables in generated code. -func (p *ParameterDescriptor) GoVariableName() string { - name := LowercaseFirstCharacter(p.GoName) - if IsGoKeyword(name) { - name = "p" + p.GoName - } - // Handle leading digits - if len(name) > 0 && name[0] >= '0' && name[0] <= '9' { - name = "n" + name - } - return name -} - -// HasOptionalPointer returns true if this parameter should be a pointer -// (optional parameters that aren't required). -func (p *ParameterDescriptor) HasOptionalPointer() bool { - if p.Required { - return false - } - // Check if schema has skip-optional-pointer extension - if p.Schema != nil && p.Schema.Extensions != nil && - p.Schema.Extensions.SkipOptionalPointer != nil && *p.Schema.Extensions.SkipOptionalPointer { - return false - } - return true -} - -// RequestBodyDescriptor describes a request body for a specific content type. -type RequestBodyDescriptor struct { - ContentType string // "application/json", "multipart/form-data", etc. - Required bool - Schema *SchemaDescriptor - - // Precomputed for templates - NameTag string // "JSON", "Formdata", "Multipart", "Text", etc. - GoTypeName string // "{OperationID}JSONBody", etc. - FuncSuffix string // "", "WithJSONBody", "WithFormBody" (empty for default) - IsDefault bool // Is this the default body type? - IsJSON bool // Is this a JSON content type? - - // Encoding options for form data - Encoding map[string]RequestBodyEncoding -} - -// RequestBodyEncoding describes encoding options for a form field. -type RequestBodyEncoding struct { - ContentType string - Style string - Explode *bool -} - -// ResponseDescriptor describes a response for a status code. -type ResponseDescriptor struct { - StatusCode string // "200", "404", "default", "2XX" - Description string - Contents []*ResponseContentDescriptor - Headers []*ResponseHeaderDescriptor - Ref string // If this is a reference to a named response -} - -// GoName returns a Go-safe name for this response (e.g., "200" -> "200", "default" -> "Default"). -func (r *ResponseDescriptor) GoName() string { - return ToCamelCase(r.StatusCode) -} - -// HasFixedStatusCode returns true if the status code is a specific number (not "default" or "2XX"). -func (r *ResponseDescriptor) HasFixedStatusCode() bool { - if r.StatusCode == "default" { - return false - } - // Check for wildcard patterns like "2XX" - if strings.HasSuffix(strings.ToUpper(r.StatusCode), "XX") { - return false - } - return true -} - -// ResponseContentDescriptor describes response content for a content type. -type ResponseContentDescriptor struct { - ContentType string - Schema *SchemaDescriptor - NameTag string // "JSON", "XML", etc. - IsJSON bool -} - -// ResponseHeaderDescriptor describes a response header. -type ResponseHeaderDescriptor struct { - Name string - GoName string - Required bool - Schema *SchemaDescriptor -} - -// SecurityRequirement describes a security requirement for an operation. -type SecurityRequirement struct { - Name string // Security scheme name - Scopes []string // Required scopes (for OAuth2) -} - -// Helper functions for computing descriptor fields - -// ComputeStyleFunc returns the style function name for a parameter. -func ComputeStyleFunc(style string, explode bool) string { - base := "Style" + ToCamelCase(style) - if explode { - return base + "ExplodeParam" - } - return base + "Param" -} - -// ComputeBindFunc returns the bind function name for a parameter. -func ComputeBindFunc(style string, explode bool) string { - base := "Bind" + ToCamelCase(style) - if explode { - return base + "ExplodeParam" - } - return base + "Param" -} - -// ComputeBodyNameTag returns the name tag for a content type. -func ComputeBodyNameTag(contentType string) string { - switch { - case contentType == "application/json": - return "JSON" - case IsMediaTypeJSON(contentType): - return MediaTypeToCamelCase(contentType) - case strings.HasPrefix(contentType, "multipart/"): - return "Multipart" - case contentType == "application/x-www-form-urlencoded": - return "Formdata" - case contentType == "text/plain": - return "Text" - case strings.HasPrefix(contentType, "application/xml") || strings.HasSuffix(contentType, "+xml"): - return "XML" - default: - return "" - } -} - -// IsMediaTypeJSON returns true if the content type is a JSON media type. -func IsMediaTypeJSON(contentType string) bool { - if contentType == "application/json" { - return true - } - if strings.HasSuffix(contentType, "+json") { - return true - } - if strings.Contains(contentType, "json") { - return true - } - return false -} - -// MediaTypeToCamelCase converts a media type to a CamelCase identifier. -func MediaTypeToCamelCase(mediaType string) string { - // application/vnd.api+json -> ApplicationVndApiJson - mediaType = strings.ReplaceAll(mediaType, "/", " ") - mediaType = strings.ReplaceAll(mediaType, "+", " ") - mediaType = strings.ReplaceAll(mediaType, ".", " ") - mediaType = strings.ReplaceAll(mediaType, "-", " ") - return ToCamelCase(mediaType) -} diff --git a/experimental/internal/codegen/output.go b/experimental/internal/codegen/output.go deleted file mode 100644 index 0793124223..0000000000 --- a/experimental/internal/codegen/output.go +++ /dev/null @@ -1,764 +0,0 @@ -package codegen - -import ( - "bytes" - "fmt" - "sort" - "strings" - - "golang.org/x/tools/imports" -) - -// Output collects generated Go code and formats it. -type Output struct { - packageName string - imports map[string]string // path -> alias - types []string // type definitions in order -} - -// NewOutput creates a new output collector. -func NewOutput(packageName string) *Output { - return &Output{ - packageName: packageName, - imports: make(map[string]string), - } -} - -// AddImport adds an import path with optional alias. -func (o *Output) AddImport(path, alias string) { - if path == "" { - return - } - o.imports[path] = alias -} - -// AddImports adds multiple imports from a map. -func (o *Output) AddImports(imports map[string]string) { - for path, alias := range imports { - o.AddImport(path, alias) - } -} - -// AddType adds a type definition to the output. -func (o *Output) AddType(code string) { - if code != "" { - o.types = append(o.types, code) - } -} - -// String generates the complete Go source file. -func (o *Output) String() string { - var buf bytes.Buffer - - // Generated code header (tells linters to skip this file) - buf.WriteString("// Code generated by oapi-codegen; DO NOT EDIT.\n\n") - - // Package declaration - fmt.Fprintf(&buf, "package %s\n\n", o.packageName) - - // Imports - if len(o.imports) > 0 { - buf.WriteString("import (\n") - paths := make([]string, 0, len(o.imports)) - for path := range o.imports { - paths = append(paths, path) - } - sort.Strings(paths) - - for _, path := range paths { - alias := o.imports[path] - if alias != "" { - fmt.Fprintf(&buf, "\t%s %q\n", alias, path) - } else { - fmt.Fprintf(&buf, "\t%q\n", path) - } - } - buf.WriteString(")\n\n") - } - - // Types - for _, t := range o.types { - buf.WriteString(t) - buf.WriteString("\n\n") - } - - return buf.String() -} - -// Format returns the formatted Go source code with imports organized. -func (o *Output) Format() (string, error) { - src := o.String() - formatted, err := imports.Process("", []byte(src), nil) - if err != nil { - return src, fmt.Errorf("formatting output: %w (source:\n%s)", err, src) - } - return string(formatted), nil -} - -// CodeBuilder helps construct Go code fragments. -type CodeBuilder struct { - buf bytes.Buffer - indent int -} - -// NewCodeBuilder creates a new code builder. -func NewCodeBuilder() *CodeBuilder { - return &CodeBuilder{} -} - -// Indent increases indentation. -func (b *CodeBuilder) Indent() { - b.indent++ -} - -// Dedent decreases indentation. -func (b *CodeBuilder) Dedent() { - if b.indent > 0 { - b.indent-- - } -} - -// Line writes a line with current indentation. -func (b *CodeBuilder) Line(format string, args ...any) { - for i := 0; i < b.indent; i++ { - b.buf.WriteByte('\t') - } - if len(args) > 0 { - fmt.Fprintf(&b.buf, format, args...) - } else { - b.buf.WriteString(format) - } - b.buf.WriteByte('\n') -} - -// BlankLine writes an empty line. -func (b *CodeBuilder) BlankLine() { - b.buf.WriteByte('\n') -} - -// Raw writes raw text without indentation or newline. -func (b *CodeBuilder) Raw(s string) { - b.buf.WriteString(s) -} - -// String returns the built code. -func (b *CodeBuilder) String() string { - return b.buf.String() -} - -// GenerateStruct generates a struct type definition. -func GenerateStruct(name string, fields []StructField, doc string, tagGen *StructTagGenerator) string { - b := NewCodeBuilder() - - // Type documentation - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - b.Line("type %s struct {", name) - b.Indent() - - for _, f := range fields { - tag := generateFieldTag(f, tagGen) - if f.Doc != "" { - // Single line comment for field - b.Line("%s %s %s // %s", f.Name, f.Type, tag, f.Doc) - } else { - b.Line("%s %s %s", f.Name, f.Type, tag) - } - } - - b.Dedent() - b.Line("}") - - return b.String() -} - -// generateFieldTag generates the struct tag for a field. -func generateFieldTag(f StructField, tagGen *StructTagGenerator) string { - if tagGen == nil { - if f.JSONIgnore { - return "`json:\"-\"`" - } - return FormatJSONTag(f.JSONName, f.OmitEmpty) - } - info := StructTagInfo{ - FieldName: f.JSONName, - GoFieldName: f.Name, - IsOptional: !f.Required, - IsNullable: f.Nullable, - IsPointer: f.Pointer, - OmitEmpty: f.OmitEmpty, - OmitZero: f.OmitZero, - JSONIgnore: f.JSONIgnore, - } - return tagGen.GenerateTags(info) -} - -// GenerateStructWithAdditionalProps generates a struct with AdditionalProperties field -// and custom marshal/unmarshal methods. -func GenerateStructWithAdditionalProps(name string, fields []StructField, addPropsType string, doc string, tagGen *StructTagGenerator) string { - b := NewCodeBuilder() - - // Type documentation - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - b.Line("type %s struct {", name) - b.Indent() - - // Regular fields - for _, f := range fields { - tag := generateFieldTag(f, tagGen) - b.Line("%s %s %s", f.Name, f.Type, tag) - } - - // AdditionalProperties field - b.Line("AdditionalProperties map[string]%s `json:\"-\"`", addPropsType) - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateTypeAlias generates a type alias definition. -func GenerateTypeAlias(name, targetType, doc string) string { - b := NewCodeBuilder() - - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - b.Line("type %s = %s", name, targetType) - - return b.String() -} - -// GenerateEnum generates an enum type with const values. -// If customNames is provided and has the same length as values, those names will be used -// as the constant names instead of auto-generated ones. -func GenerateEnum(name, baseType string, values []string, customNames []string, doc string) string { - return GenerateEnumWithConstPrefix(name, name, baseType, values, customNames, doc) -} - -// GenerateEnumWithConstPrefix generates an enum type with const values. -// typeName is used for the type definition, constPrefix is used for constant names. -// This allows the type to be defined with a stable name while constants use a friendly name. -func GenerateEnumWithConstPrefix(typeName, constPrefix, baseType string, values []string, customNames []string, doc string) string { - b := NewCodeBuilder() - - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - b.Line("type %s %s", typeName, baseType) - b.BlankLine() - - if len(values) > 0 { - b.Line("const (") - b.Indent() - - // Track used names to handle duplicates - usedNames := make(map[string]int) - - for i, v := range values { - var constName string - - // Use custom name if provided, otherwise auto-generate - if len(customNames) > i && customNames[i] != "" { - constName = constPrefix + "_" + customNames[i] - } else { - constSuffix := sanitizeEnumValue(v, baseType) - constName = constPrefix + "_" + constSuffix - } - - // Handle duplicate names by adding a numeric suffix - if count, exists := usedNames[constName]; exists { - constName = fmt.Sprintf("%s_%d", constName, count) - usedNames[constName] = count + 1 - } else { - usedNames[constName] = 1 - } - - if baseType == "string" { - b.Line("%s %s = %q", constName, typeName, v) - } else { - b.Line("%s %s = %s", constName, typeName, v) - } - } - - b.Dedent() - b.Line(")") - } - - return b.String() -} - -// sanitizeEnumValue converts an enum value to a valid Go identifier suffix. -func sanitizeEnumValue(v string, baseType string) string { - // For integer enums, prefix with N for readability - if baseType == "int" || baseType == "int32" || baseType == "int64" { - // Check if it's a numeric value - if len(v) > 0 { - firstChar := v[0] - if firstChar >= '0' && firstChar <= '9' || firstChar == '-' { - // Negative numbers - if firstChar == '-' { - return "Minus" + v[1:] - } - return "N" + v - } - } - } - - // Replace common special characters - v = strings.ReplaceAll(v, "-", "_") - v = strings.ReplaceAll(v, " ", "_") - v = strings.ReplaceAll(v, ".", "_") - - // Remove any remaining invalid characters - var result strings.Builder - for i, r := range v { - if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r == '_' { - result.WriteRune(r) - } else if r >= '0' && r <= '9' && i > 0 { - result.WriteRune(r) - } - } - - if result.Len() == 0 { - return "Value" - } - return result.String() -} - -// GenerateUnionType generates a union struct for anyOf/oneOf with marshal/unmarshal. -func GenerateUnionType(name string, members []UnionMember, isOneOf bool, doc string) string { - b := NewCodeBuilder() - - if doc != "" { - for _, line := range strings.Split(doc, "\n") { - b.Line("// %s", line) - } - } - - // Generate struct with pointer field for each member - b.Line("type %s struct {", name) - b.Indent() - - for _, m := range members { - b.Line("%s *%s", m.FieldName, m.TypeName) - } - - b.Dedent() - b.Line("}") - - return b.String() -} - -// UnionMember represents a member of a union type (anyOf/oneOf). -type UnionMember struct { - FieldName string // Go field name - TypeName string // Go type name - Index int // Position in anyOf/oneOf array - HasApplyDefaults bool // Whether this type has an ApplyDefaults method -} - -// isPrimitiveType returns true if the type is a Go primitive or collection -// that doesn't have an ApplyDefaults method. -func isPrimitiveType(typeName string) bool { - switch typeName { - case "string", "int", "int8", "int16", "int32", "int64", - "uint", "uint8", "uint16", "uint32", "uint64", - "float32", "float64", "bool", "any": - return true - default: - // Slices and maps don't have ApplyDefaults - if strings.HasPrefix(typeName, "[]") || strings.HasPrefix(typeName, "map[") { - return true - } - return false - } -} - -// GenerateUnionApplyDefaults generates ApplyDefaults for a union type. -// It recurses into non-nil members that have ApplyDefaults. -func GenerateUnionApplyDefaults(name string, members []UnionMember) string { - b := NewCodeBuilder() - - b.Line("// ApplyDefaults sets default values for fields that are nil.") - b.Line("func (u *%s) ApplyDefaults() {", name) - b.Indent() - - for _, m := range members { - // Only recurse into types that have ApplyDefaults - if m.HasApplyDefaults { - b.Line("if u.%s != nil {", m.FieldName) - b.Indent() - b.Line("u.%s.ApplyDefaults()", m.FieldName) - b.Dedent() - b.Line("}") - } - } - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateUnionMarshalOneOf generates MarshalJSON for a oneOf type. -func GenerateUnionMarshalOneOf(name string, members []UnionMember) string { - b := NewCodeBuilder() - - b.Line("func (u %s) MarshalJSON() ([]byte, error) {", name) - b.Indent() - - b.Line("var count int") - b.Line("var data []byte") - b.Line("var err error") - b.BlankLine() - - for _, m := range members { - b.Line("if u.%s != nil {", m.FieldName) - b.Indent() - b.Line("count++") - b.Line("data, err = json.Marshal(u.%s)", m.FieldName) - b.Line("if err != nil {") - b.Indent() - b.Line("return nil, err") - b.Dedent() - b.Line("}") - b.Dedent() - b.Line("}") - } - - b.BlankLine() - b.Line("if count != 1 {") - b.Indent() - b.Line("return nil, fmt.Errorf(\"%s: exactly one member must be set, got %%d\", count)", name) - b.Dedent() - b.Line("}") - b.BlankLine() - b.Line("return data, nil") - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateUnionUnmarshalOneOf generates UnmarshalJSON for a oneOf type. -func GenerateUnionUnmarshalOneOf(name string, members []UnionMember) string { - b := NewCodeBuilder() - - b.Line("func (u *%s) UnmarshalJSON(data []byte) error {", name) - b.Indent() - - b.Line("var successCount int") - b.BlankLine() - - for _, m := range members { - b.Line("var v%d %s", m.Index, m.TypeName) - b.Line("if err := json.Unmarshal(data, &v%d); err == nil {", m.Index) - b.Indent() - b.Line("u.%s = &v%d", m.FieldName, m.Index) - b.Line("successCount++") - b.Dedent() - b.Line("}") - b.BlankLine() - } - - b.Line("if successCount != 1 {") - b.Indent() - b.Line("return fmt.Errorf(\"%s: expected exactly one type to match, got %%d\", successCount)", name) - b.Dedent() - b.Line("}") - b.BlankLine() - b.Line("return nil") - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateUnionMarshalAnyOf generates MarshalJSON for an anyOf type. -func GenerateUnionMarshalAnyOf(name string, members []UnionMember) string { - b := NewCodeBuilder() - - b.Line("func (u %s) MarshalJSON() ([]byte, error) {", name) - b.Indent() - - // Check if any members are objects (need field merging) - hasObjects := false - for _, m := range members { - if !isPrimitiveType(m.TypeName) { - hasObjects = true - break - } - } - - if hasObjects { - // Merge object fields - b.Line("result := make(map[string]any)") - b.BlankLine() - - for _, m := range members { - b.Line("if u.%s != nil {", m.FieldName) - b.Indent() - if isPrimitiveType(m.TypeName) { - // For primitives, we can't merge - just return the value - b.Line("return json.Marshal(u.%s)", m.FieldName) - } else { - b.Line("data, err := json.Marshal(u.%s)", m.FieldName) - b.Line("if err != nil {") - b.Indent() - b.Line("return nil, err") - b.Dedent() - b.Line("}") - b.Line("var m map[string]any") - b.Line("if err := json.Unmarshal(data, &m); err == nil {") - b.Indent() - b.Line("for k, v := range m {") - b.Indent() - b.Line("result[k] = v") - b.Dedent() - b.Line("}") - b.Dedent() - b.Line("}") - } - b.Dedent() - b.Line("}") - } - - b.BlankLine() - b.Line("return json.Marshal(result)") - } else { - // All primitives - marshal the first non-nil one - for _, m := range members { - b.Line("if u.%s != nil {", m.FieldName) - b.Indent() - b.Line("return json.Marshal(u.%s)", m.FieldName) - b.Dedent() - b.Line("}") - } - b.Line("return []byte(\"null\"), nil") - } - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateUnionUnmarshalAnyOf generates UnmarshalJSON for an anyOf type. -func GenerateUnionUnmarshalAnyOf(name string, members []UnionMember) string { - b := NewCodeBuilder() - - b.Line("func (u *%s) UnmarshalJSON(data []byte) error {", name) - b.Indent() - - for _, m := range members { - b.Line("var v%d %s", m.Index, m.TypeName) - b.Line("if err := json.Unmarshal(data, &v%d); err == nil {", m.Index) - b.Indent() - b.Line("u.%s = &v%d", m.FieldName, m.Index) - b.Dedent() - b.Line("}") - b.BlankLine() - } - - b.Line("return nil") - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateMixedPropertiesMarshal generates MarshalJSON for structs with additionalProperties. -func GenerateMixedPropertiesMarshal(name string, fields []StructField) string { - b := NewCodeBuilder() - - b.Line("func (s %s) MarshalJSON() ([]byte, error) {", name) - b.Indent() - - b.Line("result := make(map[string]any)") - b.BlankLine() - - // Copy known fields - for _, f := range fields { - if f.Pointer { - b.Line("if s.%s != nil {", f.Name) - b.Indent() - b.Line("result[%q] = s.%s", f.JSONName, f.Name) - b.Dedent() - b.Line("}") - } else { - b.Line("result[%q] = s.%s", f.JSONName, f.Name) - } - } - - b.BlankLine() - b.Line("// Add additional properties") - b.Line("for k, v := range s.AdditionalProperties {") - b.Indent() - b.Line("result[k] = v") - b.Dedent() - b.Line("}") - b.BlankLine() - b.Line("return json.Marshal(result)") - - b.Dedent() - b.Line("}") - - return b.String() -} - -// GenerateApplyDefaults generates an ApplyDefaults method for a struct. -// It sets default values for fields that are nil and have defaults defined, -// and recursively calls ApplyDefaults on nested struct fields. -// Always generates the method (even if empty) so it can be called uniformly. -func GenerateApplyDefaults(name string, fields []StructField) string { - b := NewCodeBuilder() - - b.Line("// ApplyDefaults sets default values for fields that are nil.") - b.Line("func (s *%s) ApplyDefaults() {", name) - b.Indent() - - for _, f := range fields { - // Apply defaults to nil pointer fields - if f.Default != "" && f.Pointer { - b.Line("if s.%s == nil {", f.Name) - b.Indent() - // Get the base type (without *) - baseType := strings.TrimPrefix(f.Type, "*") - // Check if we need an explicit type conversion for numeric types - // This is needed because Go infers float64 for floating point literals - // and int for integer literals, which may not match the target type - if needsTypeConversion(baseType) { - b.Line("v := %s(%s)", baseType, f.Default) - } else { - b.Line("v := %s", f.Default) - } - b.Line("s.%s = &v", f.Name) - b.Dedent() - b.Line("}") - } - - // Recursively apply defaults to struct fields - if f.IsStruct && f.Pointer { - b.Line("if s.%s != nil {", f.Name) - b.Indent() - b.Line("s.%s.ApplyDefaults()", f.Name) - b.Dedent() - b.Line("}") - } - } - - b.Dedent() - b.Line("}") - - return b.String() -} - -// needsTypeConversion returns true if a numeric type needs an explicit conversion -// from the default Go literal type (int for integers, float64 for floats). -func needsTypeConversion(goType string) bool { - switch goType { - case "int8", "int16", "int32", "int64", - "uint", "uint8", "uint16", "uint32", "uint64", - "float32": - return true - default: - return false - } -} - -// GenerateMixedPropertiesUnmarshal generates UnmarshalJSON for structs with additionalProperties. -func GenerateMixedPropertiesUnmarshal(name string, fields []StructField, addPropsType string) string { - b := NewCodeBuilder() - - b.Line("func (s *%s) UnmarshalJSON(data []byte) error {", name) - b.Indent() - - // Build set of known field names - b.Line("// Known fields") - b.Line("knownFields := map[string]bool{") - b.Indent() - for _, f := range fields { - b.Line("%q: true,", f.JSONName) - } - b.Dedent() - b.Line("}") - b.BlankLine() - - // Unmarshal into a map first - b.Line("var raw map[string]json.RawMessage") - b.Line("if err := json.Unmarshal(data, &raw); err != nil {") - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.BlankLine() - - // Unmarshal known fields - for _, f := range fields { - b.Line("if v, ok := raw[%q]; ok {", f.JSONName) - b.Indent() - if f.Pointer { - b.Line("var val %s", strings.TrimPrefix(f.Type, "*")) - b.Line("if err := json.Unmarshal(v, &val); err != nil {") - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.Line("s.%s = &val", f.Name) - } else { - b.Line("if err := json.Unmarshal(v, &s.%s); err != nil {", f.Name) - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - } - b.Dedent() - b.Line("}") - } - - b.BlankLine() - b.Line("// Collect additional properties") - b.Line("s.AdditionalProperties = make(map[string]%s)", addPropsType) - b.Line("for k, v := range raw {") - b.Indent() - b.Line("if !knownFields[k] {") - b.Indent() - b.Line("var val %s", addPropsType) - b.Line("if err := json.Unmarshal(v, &val); err != nil {") - b.Indent() - b.Line("return err") - b.Dedent() - b.Line("}") - b.Line("s.AdditionalProperties[k] = val") - b.Dedent() - b.Line("}") - b.Dedent() - b.Line("}") - b.BlankLine() - b.Line("return nil") - - b.Dedent() - b.Line("}") - - return b.String() -} diff --git a/experimental/internal/codegen/paramgen.go b/experimental/internal/codegen/paramgen.go deleted file mode 100644 index 19221ac0c0..0000000000 --- a/experimental/internal/codegen/paramgen.go +++ /dev/null @@ -1,178 +0,0 @@ -package codegen - -import ( - "fmt" - "sort" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// ParamUsageTracker tracks which parameter styling and binding functions -// are needed based on the OpenAPI spec being processed. -type ParamUsageTracker struct { - // usedStyles tracks which style/explode combinations are used. - // Keys are formatted as "style_{style}" or "style_{style}_explode" for serialization, - // and "bind_{style}" or "bind_{style}_explode" for binding. - usedStyles map[string]bool -} - -// NewParamUsageTracker creates a new ParamUsageTracker. -func NewParamUsageTracker() *ParamUsageTracker { - return &ParamUsageTracker{ - usedStyles: make(map[string]bool), - } -} - -// RecordStyleParam records that a style/explode combination is used for serialization. -// This is typically called when processing client parameters. -func (t *ParamUsageTracker) RecordStyleParam(style string, explode bool) { - key := templates.ParamStyleKey("style_", style, explode) - t.usedStyles[key] = true -} - -// RecordBindParam records that a style/explode combination is used for binding. -// This is typically called when processing server parameters. -func (t *ParamUsageTracker) RecordBindParam(style string, explode bool) { - key := templates.ParamStyleKey("bind_", style, explode) - t.usedStyles[key] = true -} - -// RecordParam records both style and bind usage for a parameter. -// Use this when generating both client and server code. -func (t *ParamUsageTracker) RecordParam(style string, explode bool) { - t.RecordStyleParam(style, explode) - t.RecordBindParam(style, explode) -} - -// HasAnyUsage returns true if any parameter functions are needed. -func (t *ParamUsageTracker) HasAnyUsage() bool { - return len(t.usedStyles) > 0 -} - -// GetRequiredTemplates returns the list of templates needed based on usage. -// The helpers template is always included first if any functions are needed. -func (t *ParamUsageTracker) GetRequiredTemplates() []templates.ParamTemplate { - if !t.HasAnyUsage() { - return nil - } - - var result []templates.ParamTemplate - - // Always include helpers first - result = append(result, templates.ParamHelpersTemplate) - - // Get all used style keys and sort them for deterministic output - keys := make([]string, 0, len(t.usedStyles)) - for key := range t.usedStyles { - keys = append(keys, key) - } - sort.Strings(keys) - - // Add each required template - for _, key := range keys { - tmpl, ok := templates.ParamTemplates[key] - if !ok { - // This shouldn't happen if keys are properly validated - continue - } - result = append(result, tmpl) - } - - return result -} - -// GetRequiredImports returns all imports needed for the used parameter functions. -// This aggregates imports from the helpers template and all used templates. -func (t *ParamUsageTracker) GetRequiredImports() []templates.Import { - if !t.HasAnyUsage() { - return nil - } - - // Use a map to deduplicate imports - importSet := make(map[string]templates.Import) - - // Add helpers imports - for _, imp := range templates.ParamHelpersTemplate.Imports { - importSet[imp.Path] = imp - } - - // Add imports from each used template - for key := range t.usedStyles { - tmpl, ok := templates.ParamTemplates[key] - if !ok { - continue - } - for _, imp := range tmpl.Imports { - importSet[imp.Path] = imp - } - } - - // Convert to sorted slice - result := make([]templates.Import, 0, len(importSet)) - for _, imp := range importSet { - result = append(result, imp) - } - sort.Slice(result, func(i, j int) bool { - return result[i].Path < result[j].Path - }) - - return result -} - -// GetUsedStyleKeys returns the sorted list of used style keys for debugging. -func (t *ParamUsageTracker) GetUsedStyleKeys() []string { - keys := make([]string, 0, len(t.usedStyles)) - for key := range t.usedStyles { - keys = append(keys, key) - } - sort.Strings(keys) - return keys -} - -// DefaultParamStyle returns the default style for a parameter location. -func DefaultParamStyle(location string) string { - switch location { - case "path", "header": - return "simple" - case "query", "cookie": - return "form" - default: - return "form" - } -} - -// DefaultParamExplode returns the default explode value for a parameter location. -func DefaultParamExplode(location string) bool { - switch location { - case "path", "header": - return false - case "query", "cookie": - return true - default: - return false - } -} - -// ValidateParamStyle validates that a style is supported for a location. -// Returns an error if the combination is invalid. -func ValidateParamStyle(style, location string) error { - validStyles := map[string][]string{ - "path": {"simple", "label", "matrix"}, - "query": {"form", "spaceDelimited", "pipeDelimited", "deepObject"}, - "header": {"simple"}, - "cookie": {"form"}, - } - - allowed, ok := validStyles[location] - if !ok { - return fmt.Errorf("unknown parameter location: %s", location) - } - - for _, s := range allowed { - if s == style { - return nil - } - } - - return fmt.Errorf("style '%s' is not valid for location '%s'; valid styles are: %v", style, location, allowed) -} diff --git a/experimental/internal/codegen/paramgen_test.go b/experimental/internal/codegen/paramgen_test.go deleted file mode 100644 index a80de1e40d..0000000000 --- a/experimental/internal/codegen/paramgen_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestParamUsageTracker(t *testing.T) { - t.Run("empty tracker has no usage", func(t *testing.T) { - tracker := NewParamUsageTracker() - assert.False(t, tracker.HasAnyUsage()) - assert.Empty(t, tracker.GetRequiredTemplates()) - assert.Empty(t, tracker.GetRequiredImports()) - }) - - t.Run("records style param", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordStyleParam("simple", false) - - assert.True(t, tracker.HasAnyUsage()) - keys := tracker.GetUsedStyleKeys() - assert.Contains(t, keys, "style_simple") - }) - - t.Run("records style param with explode", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordStyleParam("form", true) - - keys := tracker.GetUsedStyleKeys() - assert.Contains(t, keys, "style_form_explode") - }) - - t.Run("records bind param", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordBindParam("label", false) - - keys := tracker.GetUsedStyleKeys() - assert.Contains(t, keys, "bind_label") - }) - - t.Run("records both style and bind", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordParam("matrix", true) - - keys := tracker.GetUsedStyleKeys() - assert.Contains(t, keys, "style_matrix_explode") - assert.Contains(t, keys, "bind_matrix_explode") - }) - - t.Run("returns helpers template first", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordStyleParam("simple", false) - - templates := tracker.GetRequiredTemplates() - require.NotEmpty(t, templates) - assert.Equal(t, "helpers", templates[0].Name) - }) - - t.Run("aggregates imports", func(t *testing.T) { - tracker := NewParamUsageTracker() - tracker.RecordStyleParam("simple", false) - tracker.RecordStyleParam("form", true) - - imports := tracker.GetRequiredImports() - assert.NotEmpty(t, imports) - - // Check that common imports are included - paths := make([]string, len(imports)) - for i, imp := range imports { - paths[i] = imp.Path - } - assert.Contains(t, paths, "reflect") - assert.Contains(t, paths, "strings") - }) -} - -func TestDefaultParamStyle(t *testing.T) { - tests := []struct { - location string - expected string - }{ - {"path", "simple"}, - {"header", "simple"}, - {"query", "form"}, - {"cookie", "form"}, - {"unknown", "form"}, - } - - for _, tc := range tests { - t.Run(tc.location, func(t *testing.T) { - assert.Equal(t, tc.expected, DefaultParamStyle(tc.location)) - }) - } -} - -func TestDefaultParamExplode(t *testing.T) { - tests := []struct { - location string - expected bool - }{ - {"path", false}, - {"header", false}, - {"query", true}, - {"cookie", true}, - {"unknown", false}, - } - - for _, tc := range tests { - t.Run(tc.location, func(t *testing.T) { - assert.Equal(t, tc.expected, DefaultParamExplode(tc.location)) - }) - } -} - -func TestValidateParamStyle(t *testing.T) { - validCases := []struct { - style string - location string - }{ - {"simple", "path"}, - {"label", "path"}, - {"matrix", "path"}, - {"form", "query"}, - {"spaceDelimited", "query"}, - {"pipeDelimited", "query"}, - {"deepObject", "query"}, - {"simple", "header"}, - {"form", "cookie"}, - } - - for _, tc := range validCases { - t.Run(tc.style+"_in_"+tc.location, func(t *testing.T) { - err := ValidateParamStyle(tc.style, tc.location) - assert.NoError(t, err) - }) - } - - invalidCases := []struct { - style string - location string - }{ - {"deepObject", "path"}, - {"matrix", "query"}, - {"label", "header"}, - {"simple", "cookie"}, - } - - for _, tc := range invalidCases { - t.Run(tc.style+"_in_"+tc.location+"_invalid", func(t *testing.T) { - err := ValidateParamStyle(tc.style, tc.location) - assert.Error(t, err) - }) - } - - t.Run("unknown location", func(t *testing.T) { - err := ValidateParamStyle("simple", "body") - assert.Error(t, err) - }) -} diff --git a/experimental/internal/codegen/receivergen.go b/experimental/internal/codegen/receivergen.go deleted file mode 100644 index e57fef3929..0000000000 --- a/experimental/internal/codegen/receivergen.go +++ /dev/null @@ -1,131 +0,0 @@ -package codegen - -import ( - "bytes" - "fmt" - "strings" - "text/template" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// ReceiverTemplateData is passed to receiver templates. -type ReceiverTemplateData struct { - Prefix string // "Webhook" or "Callback" - PrefixLower string // "webhook" or "callback" - Operations []*OperationDescriptor // Operations to generate for -} - -// ReceiverGenerator generates receiver code from operation descriptors. -// It is parameterized by prefix to support both webhooks and callbacks. -type ReceiverGenerator struct { - tmpl *template.Template - prefix string // "Webhook" or "Callback" - serverType string -} - -// NewReceiverGenerator creates a new receiver generator for the specified server type. -func NewReceiverGenerator(prefix string, serverType string) (*ReceiverGenerator, error) { - if serverType == "" { - return nil, fmt.Errorf("%s receiver requires a server type to be set", prefix) - } - - tmpl := template.New("receiver").Funcs(templates.Funcs()) - - // Get receiver templates for the specified server type - receiverTemplates, err := getReceiverTemplates(serverType) - if err != nil { - return nil, err - } - - // Parse receiver-specific templates - for _, ct := range receiverTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + ct.Template) - if err != nil { - return nil, fmt.Errorf("failed to read receiver template %s: %w", ct.Template, err) - } - _, err = tmpl.New(ct.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse receiver template %s: %w", ct.Template, err) - } - } - - // Parse shared templates (errors, param_types) - for _, st := range templates.SharedServerTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + st.Template) - if err != nil { - return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) - } - _, err = tmpl.New(st.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) - } - } - - return &ReceiverGenerator{ - tmpl: tmpl, - prefix: prefix, - serverType: serverType, - }, nil -} - -// getReceiverTemplates returns the receiver templates for the specified server type. -func getReceiverTemplates(serverType string) (map[string]templates.ReceiverTemplate, error) { - switch serverType { - case ServerTypeStdHTTP: - return templates.StdHTTPReceiverTemplates, nil - case ServerTypeChi: - return templates.ChiReceiverTemplates, nil - case ServerTypeEcho: - return templates.EchoReceiverTemplates, nil - case ServerTypeEchoV4: - return templates.EchoV4ReceiverTemplates, nil - case ServerTypeGin: - return templates.GinReceiverTemplates, nil - case ServerTypeGorilla: - return templates.GorillaReceiverTemplates, nil - case ServerTypeFiber: - return templates.FiberReceiverTemplates, nil - case ServerTypeIris: - return templates.IrisReceiverTemplates, nil - default: - return nil, fmt.Errorf("unsupported server type for receiver: %q", serverType) - } -} - -func (g *ReceiverGenerator) templateData(ops []*OperationDescriptor) ReceiverTemplateData { - return ReceiverTemplateData{ - Prefix: g.prefix, - PrefixLower: strings.ToLower(g.prefix), - Operations: ops, - } -} - -// GenerateReceiver generates the receiver interface and handler functions. -func (g *ReceiverGenerator) GenerateReceiver(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - - if err := g.tmpl.ExecuteTemplate(&buf, "receiver", g.templateData(ops)); err != nil { - return "", fmt.Errorf("generating receiver code: %w", err) - } - - return buf.String(), nil -} - -// GenerateParamTypes generates the parameter struct types. -func (g *ReceiverGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateErrors generates error types (shared with server). -func (g *ReceiverGenerator) GenerateErrors() (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "errors", nil); err != nil { - return "", err - } - return buf.String(), nil -} diff --git a/experimental/internal/codegen/schema.go b/experimental/internal/codegen/schema.go deleted file mode 100644 index bb0770bb65..0000000000 --- a/experimental/internal/codegen/schema.go +++ /dev/null @@ -1,117 +0,0 @@ -package codegen - -import ( - "strings" - - "github.com/pb33f/libopenapi/datamodel/high/base" -) - -// SchemaPath represents the location of a schema in the OpenAPI document. -// Used for deriving type names and disambiguating collisions. -// Example: ["components", "schemas", "Pet", "properties", "address"] -type SchemaPath []string - -// String returns the path as a JSON pointer-style string. -func (p SchemaPath) String() string { - return "#/" + strings.Join(p, "/") -} - -// Append returns a new SchemaPath with the given elements appended. -// This creates a fresh slice to avoid aliasing issues with append. -func (p SchemaPath) Append(elements ...string) SchemaPath { - result := make(SchemaPath, len(p)+len(elements)) - copy(result, p) - copy(result[len(p):], elements) - return result -} - -// ContainsProperties returns true if this path contains "properties" anywhere. -// This indicates it's an inline property schema rather than a component schema. -func (p SchemaPath) ContainsProperties() bool { - for _, element := range p { - if element == "properties" { - return true - } - } - return false -} - -// SchemaDescriptor represents a schema found during the first pass through the spec. -type SchemaDescriptor struct { - // Path is where this schema appears in the document - Path SchemaPath - - // Ref is the $ref string if this is a reference (e.g., "#/components/schemas/Pet") - // Empty if this is an inline schema definition - Ref string - - // Schema is the underlying schema from libopenapi - // nil for unresolved external references - Schema *base.Schema - - // Parent points to the containing schema (nil for top-level schemas) - Parent *SchemaDescriptor - - // StableName is the deterministic Go type name derived from the full path. - // This name is stable across spec changes and should be used for type definitions. - // Example: #/components/schemas/Cat -> CatSchemaComponent - StableName string - - // ShortName is a friendly alias that may change due to deduplication. - // Generated as a type alias pointing to StableName. - ShortName string - - // OperationID is the operationId from the path operation, if this schema - // comes from a path's request body or response. Used for friendlier naming. - OperationID string - - // ContentType is the media type (e.g., "application/json") if this schema - // comes from a request body or response content. Used for naming. - ContentType string - - // Extensions holds parsed x- extension values for this schema. - // These control code generation behavior (type overrides, field names, etc.) - Extensions *Extensions - - // Recursive structure: - Properties map[string]*SchemaDescriptor - Items *SchemaDescriptor - AllOf []*SchemaDescriptor - AnyOf []*SchemaDescriptor - OneOf []*SchemaDescriptor - AdditionalProps *SchemaDescriptor -} - -// IsReference returns true if this schema is a $ref to another schema -func (d *SchemaDescriptor) IsReference() bool { - return d.Ref != "" -} - -// IsExternalReference returns true if this is a reference to an external file. -// External refs have the format: file.yaml#/path/to/schema -func (d *SchemaDescriptor) IsExternalReference() bool { - if d.Ref == "" { - return false - } - // External refs contain # but don't start with it - return !strings.HasPrefix(d.Ref, "#") && strings.Contains(d.Ref, "#") -} - -// ParseExternalRef splits an external reference into its file path and internal path. -// For "common/api.yaml#/components/schemas/Pet", returns ("common/api.yaml", "#/components/schemas/Pet"). -// Returns empty strings if not an external ref. -func (d *SchemaDescriptor) ParseExternalRef() (filePath, internalPath string) { - if !d.IsExternalReference() { - return "", "" - } - parts := strings.SplitN(d.Ref, "#", 2) - if len(parts) != 2 { - return "", "" - } - return parts[0], "#" + parts[1] -} - -// IsComponentSchema returns true if this schema is defined in #/components/schemas -func (d *SchemaDescriptor) IsComponentSchema() bool { - return len(d.Path) >= 2 && d.Path[0] == "components" && d.Path[1] == "schemas" -} diff --git a/experimental/internal/codegen/schemanames.go b/experimental/internal/codegen/schemanames.go deleted file mode 100644 index c41e8b6cef..0000000000 --- a/experimental/internal/codegen/schemanames.go +++ /dev/null @@ -1,812 +0,0 @@ -package codegen - -import ( - "fmt" - "strings" -) - -// SchemaContext identifies what kind of schema this is based on its location. -type SchemaContext int - -const ( - ContextUnknown SchemaContext = iota - ContextComponentSchema - ContextParameter - ContextRequestBody - ContextResponse - ContextHeader - ContextCallback - ContextWebhook - ContextProperty - ContextItems - ContextAllOf - ContextAnyOf - ContextOneOf - ContextAdditionalProperties -) - -// ComputeSchemaNames assigns StableName and ShortName to each schema descriptor. -// StableName is deterministic from the path; ShortName is a friendly alias. -// If a schema has a TypeNameOverride extension, that takes precedence over computed names. -func ComputeSchemaNames(schemas []*SchemaDescriptor, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) { - // First: compute stable names from full paths - for _, s := range schemas { - // Check for TypeNameOverride extension - if s.Extensions != nil && s.Extensions.TypeNameOverride != "" { - s.StableName = s.Extensions.TypeNameOverride - } else { - s.StableName = computeStableName(s.Path, converter) - } - } - - // Second: generate candidate short names - candidates := make(map[*SchemaDescriptor]string) - for _, s := range schemas { - // TypeNameOverride also applies to short names - if s.Extensions != nil && s.Extensions.TypeNameOverride != "" { - candidates[s] = s.Extensions.TypeNameOverride - } else { - candidates[s] = generateCandidateName(s, converter, contentTypeNamer) - } - } - - // Third: detect collisions and resolve them for short names - resolveCollisions(schemas, candidates, converter) - - // Assign final short names - for _, s := range schemas { - s.ShortName = candidates[s] - } -} - -// computeStableName generates a deterministic type name from the full path. -// The format is: {meaningful_names}{reversed_context_suffix} -// Example: #/components/schemas/Cat -> CatSchemaComponent -func computeStableName(path SchemaPath, converter *NameConverter) string { - if len(path) == 0 { - return "Schema" - } - - // Separate path into name parts and context parts - var nameParts []string - var contextParts []string - - for i := 0; i < len(path); i++ { - part := path[i] - // Strip leading slash from API paths (e.g., "/pets" -> "pets") - part = strings.TrimPrefix(part, "/") - if part == "" { - continue - } - if isContextKeyword(part) { - contextParts = append(contextParts, part) - } else { - nameParts = append(nameParts, part) - } - } - - // Build the name: names first, then reversed context as suffix - var result strings.Builder - - // Add name parts - // First part uses ToTypeName (adds numeric prefix if needed) - // Subsequent parts use ToTypeNamePart (no numeric prefix since they're not at the start) - for i, name := range nameParts { - if i == 0 { - result.WriteString(converter.ToTypeName(name)) - } else { - result.WriteString(converter.ToTypeNamePart(name)) - } - } - - // Add reversed context as suffix (singularized) - for i := len(contextParts) - 1; i >= 0; i-- { - suffix := contextToSuffix(contextParts[i]) - result.WriteString(suffix) - } - - name := result.String() - if name == "" { - return "Schema" - } - return name -} - -// isContextKeyword returns true if the path segment is a structural keyword -// rather than a user-defined name. -func isContextKeyword(s string) bool { - switch s { - case "components", "schemas", "parameters", "responses", "requestBodies", - "headers", "callbacks", "paths", "webhooks", - "properties", "items", "additionalProperties", - "allOf", "anyOf", "oneOf", "not", - "prefixItems", "contains", "if", "then", "else", - "dependentSchemas", "patternProperties", "propertyNames", - "unevaluatedItems", "unevaluatedProperties", - "content", "schema", "requestBody": - return true - default: - return false - } -} - -// contextToSuffix converts a context keyword to its singular suffix form. -func contextToSuffix(context string) string { - switch context { - case "components": - return "Component" - case "schemas": - return "Schema" - case "parameters": - return "Parameter" - case "responses": - return "Response" - case "requestBodies", "requestBody": - return "Request" - case "headers": - return "Header" - case "callbacks": - return "Callback" - case "paths": - return "Path" - case "webhooks": - return "Webhook" - case "properties": - return "Property" - case "items": - return "Item" - case "additionalProperties": - return "Value" - case "allOf": - return "AllOf" - case "anyOf": - return "AnyOf" - case "oneOf": - return "OneOf" - case "not": - return "Not" - case "prefixItems": - return "PrefixItem" - case "contains": - return "Contains" - case "if": - return "If" - case "then": - return "Then" - case "else": - return "Else" - case "content": - return "Content" - case "schema": - return "" // Skip redundant "Schema" suffix from content/schema - default: - return "" - } -} - -// generateCandidateName creates a candidate short name based on the schema's path. -func generateCandidateName(s *SchemaDescriptor, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { - path := s.Path - if len(path) == 0 { - return "Schema" - } - - ctx, parts := parsePathContext(path) - - switch ctx { - case ContextComponentSchema: - // #/components/schemas/Cat -> "Cat" - // #/components/schemas/Cat/properties/name -> "CatName" - return buildComponentSchemaName(parts, converter) - - case ContextParameter: - // Always suffix with Parameter - return buildParameterName(parts, converter) - - case ContextRequestBody: - // Use operationId if available for nicer names, but only for the direct request body schema - // (not nested items, properties, etc.) - if s.OperationID != "" && isDirectBodySchema(path) { - return buildOperationRequestName(s.OperationID, s.ContentType, converter, contentTypeNamer) - } - return buildRequestBodyName(parts, converter) - - case ContextResponse: - // Use operationId if available for nicer names, but only for the direct response schema - // (not nested items, properties, etc.) - if s.OperationID != "" && isDirectBodySchema(path) { - // Extract status code from path - statusCode := extractStatusCode(parts) - return buildOperationResponseName(s.OperationID, statusCode, s.ContentType, converter, contentTypeNamer) - } - return buildResponseName(parts, converter) - - case ContextHeader: - return buildHeaderName(parts, converter) - - case ContextCallback: - return buildCallbackName(parts, converter) - - case ContextWebhook: - return buildWebhookName(parts, converter) - - default: - // Fallback: join all meaningful parts - return buildFallbackName(path, converter) - } -} - -// parsePathContext determines the schema context and extracts relevant path parts. -func parsePathContext(path SchemaPath) (SchemaContext, []string) { - if len(path) == 0 { - return ContextUnknown, nil - } - - switch path[0] { - case "components": - if len(path) >= 3 && path[1] == "schemas" { - return ContextComponentSchema, path[2:] - } - if len(path) >= 3 && path[1] == "parameters" { - return ContextParameter, path[2:] - } - if len(path) >= 3 && path[1] == "requestBodies" { - return ContextRequestBody, path[2:] - } - if len(path) >= 3 && path[1] == "responses" { - return ContextResponse, path[2:] - } - if len(path) >= 3 && path[1] == "headers" { - return ContextHeader, path[2:] - } - if len(path) >= 3 && path[1] == "callbacks" { - return ContextCallback, path[2:] - } - - case "paths": - // paths/{path}/{method}/... - if len(path) >= 3 { - remaining := path[3:] // skip paths, {path}, {method} - return detectPathsContext(remaining), path[1:] // include path and method - } - - case "webhooks": - return ContextWebhook, path[1:] - } - - return ContextUnknown, path -} - -// detectPathsContext determines context from within a path item. -func detectPathsContext(remaining SchemaPath) SchemaContext { - if len(remaining) == 0 { - return ContextUnknown - } - - switch remaining[0] { - case "parameters": - return ContextParameter - case "requestBody": - return ContextRequestBody - case "responses": - return ContextResponse - case "callbacks": - return ContextCallback - } - - return ContextUnknown -} - -// buildComponentSchemaName builds a name for a component schema. -// e.g., ["Cat"] -> "Cat", ["Cat", "properties", "name"] -> "CatName" -func buildComponentSchemaName(parts []string, converter *NameConverter) string { - if len(parts) == 0 { - return "Schema" - } - - var nameParts []string - nameParts = append(nameParts, parts[0]) // schema name - - // Track trailing structural elements (only add suffix if they're at the end) - trailingSuffix := "" - - // Process nested parts - for i := 1; i < len(parts); i++ { - part := parts[i] - switch part { - case "properties": - // Skip, but next part (property name) will be added - // Clear trailing suffix since we're going deeper - trailingSuffix = "" - continue - case "items": - // Accumulate Item suffix (for nested arrays) - trailingSuffix += "Item" - continue - case "additionalProperties": - // Set Value suffix - trailingSuffix = "Value" - continue - case "allOf", "anyOf", "oneOf": - // Include the composition type and index - trailingSuffix = "" // Clear since we're adding meaningful content - if i+1 < len(parts) { - nameParts = append(nameParts, part+parts[i+1]) - i++ // Skip the index - } else { - nameParts = append(nameParts, part) - } - case "not", "prefixItems", "contains", "if", "then", "else": - // Include these structural keywords - trailingSuffix = "" - nameParts = append(nameParts, part) - default: - // Include meaningful parts (property names, indices) - // Clear trailing suffix since we have a meaningful name part - trailingSuffix = "" - nameParts = append(nameParts, part) - } - } - - name := converter.ToTypeName(strings.Join(nameParts, "_")) - - // Add trailing structural suffix if still present - if trailingSuffix != "" { - name += trailingSuffix - } - - return name -} - -// buildParameterName builds a name for a parameter schema. -func buildParameterName(parts []string, converter *NameConverter) string { - // parts could be: - // - from components/parameters: [paramName, "schema"] - // - from paths: [path, method, "parameters", index, "schema"] - - var baseName string - if len(parts) >= 2 && parts[0] != "" { - // Try to extract operation-style name - baseName = buildOperationName(parts, converter) - } - if baseName == "" && len(parts) > 0 { - baseName = converter.ToTypeName(parts[0]) - } - if baseName == "" { - baseName = "Param" - } - - // Always add Parameter suffix - if !strings.HasSuffix(baseName, "Parameter") { - baseName += "Parameter" - } - return baseName -} - -// buildRequestBodyName builds a name for a request body schema. -func buildRequestBodyName(parts []string, converter *NameConverter) string { - var baseName string - if len(parts) >= 2 { - baseName = buildOperationName(parts, converter) - } - if baseName == "" && len(parts) > 0 { - baseName = converter.ToTypeName(parts[0]) - } - if baseName == "" { - baseName = "Request" - } - - // Always add Request suffix - if !strings.HasSuffix(baseName, "Request") { - baseName += "Request" - } - return baseName -} - -// buildResponseName builds a name for a response schema. -func buildResponseName(parts []string, converter *NameConverter) string { - var baseName string - var statusCode string - - if len(parts) >= 4 { - // paths: [path, method, "responses", code, ...] - baseName = buildOperationName(parts[:2], converter) - // Find status code - for i, p := range parts { - if p == "responses" && i+1 < len(parts) { - statusCode = parts[i+1] - break - } - } - } - if baseName == "" && len(parts) > 0 { - baseName = converter.ToTypeName(parts[0]) - } - if baseName == "" { - baseName = "Response" - } - - // Add status code if present - if statusCode != "" && statusCode != "default" { - baseName += statusCode - } - - // Always add Response suffix - if !strings.HasSuffix(baseName, "Response") { - baseName += "Response" - } - return baseName -} - -// buildHeaderName builds a name for a header schema. -func buildHeaderName(parts []string, converter *NameConverter) string { - if len(parts) == 0 { - return "Header" - } - baseName := converter.ToTypeName(parts[0]) - if !strings.HasSuffix(baseName, "Header") { - baseName += "Header" - } - return baseName -} - -// buildCallbackName builds a name for a callback schema. -func buildCallbackName(parts []string, converter *NameConverter) string { - if len(parts) == 0 { - return "Callback" - } - return converter.ToTypeName(parts[0]) + "Callback" -} - -// buildWebhookName builds a name for a webhook schema. -func buildWebhookName(parts []string, converter *NameConverter) string { - if len(parts) == 0 { - return "Webhook" - } - return converter.ToTypeName(parts[0]) + "Webhook" -} - -// buildOperationName builds a name from path and method. -// e.g., ["/pets", "get"] -> "GetPets" -func buildOperationName(parts []string, converter *NameConverter) string { - if len(parts) < 2 { - return "" - } - - pathStr := parts[0] - method := parts[1] - - // Convert method to title case - methodName := converter.ToTypeName(method) - - // Convert path to name parts - // /pets/{petId}/toys -> PetsPetIdToys - pathName := pathToName(pathStr, converter) - - return methodName + pathName -} - -// pathToName converts an API path to a name component. -// e.g., "/pets/{petId}" -> "PetsPetId" -func pathToName(path string, converter *NameConverter) string { - // Remove leading slash - path = strings.TrimPrefix(path, "/") - - // Split by slash - segments := strings.Split(path, "/") - - var parts []string - for _, seg := range segments { - if seg == "" { - continue - } - // Remove braces from path parameters - seg = strings.TrimPrefix(seg, "{") - seg = strings.TrimSuffix(seg, "}") - parts = append(parts, seg) - } - - return converter.ToTypeName(strings.Join(parts, "_")) -} - -// buildFallbackName creates a name from the full path as a last resort. -func buildFallbackName(path SchemaPath, converter *NameConverter) string { - var parts []string - for _, p := range path { - // Skip common structural elements - switch p { - case "components", "schemas", "paths", "properties", - "items", "schema", "content", "application/json": - continue - default: - parts = append(parts, p) - } - } - - if len(parts) == 0 { - return "Schema" - } - - return converter.ToTypeName(strings.Join(parts, "_")) -} - -// schemaContextSuffix maps a SchemaContext to a disambiguation suffix. -func schemaContextSuffix(ctx SchemaContext) string { - switch ctx { - case ContextComponentSchema: - return "Schema" - case ContextParameter: - return "Parameter" - case ContextRequestBody: - return "Request" - case ContextResponse: - return "Response" - case ContextHeader: - return "Header" - case ContextCallback: - return "Callback" - case ContextWebhook: - return "Webhook" - default: - return "" - } -} - -// resolveCollisions detects name collisions and makes them unique. -// Reference schemas are excluded from collision detection because they don't -// generate types — their names are only used for type resolution lookups. -// -// Resolution proceeds in phases: -// 1. Context suffix: append a suffix derived from the schema's location -// (e.g. "Request", "Response"). If exactly one collider lives under -// components/schemas it keeps the bare name. -// 2. Existing disambiguateName logic (content type, status code, composition). -// 3. Numeric fallback as a last resort. -func resolveCollisions(schemas []*SchemaDescriptor, candidates map[*SchemaDescriptor]string, converter *NameConverter) { - // Filter out reference schemas — they don't generate types so their - // short names can safely shadow non-ref names without causing a collision. - var nonRefSchemas []*SchemaDescriptor - for _, s := range schemas { - if s.Ref == "" { - nonRefSchemas = append(nonRefSchemas, s) - } - } - - maxIterations := 10 // Prevent infinite loops - - for iteration := range maxIterations { - // Group non-ref schemas by candidate name - byName := make(map[string][]*SchemaDescriptor) - for _, s := range nonRefSchemas { - name := candidates[s] - byName[name] = append(byName[name], s) - } - - // Check if there are any collisions - hasCollisions := false - for _, group := range byName { - if len(group) > 1 { - hasCollisions = true - break - } - } - - if !hasCollisions { - return // All names are unique - } - - // Resolve collisions - for _, group := range byName { - if len(group) <= 1 { - continue // No collision - } - - // On last iteration, just add numeric suffixes - if iteration == maxIterations-1 { - for i, s := range group { - candidates[s] = fmt.Sprintf("%s%d", candidates[s], i+1) - } - continue - } - - // First iteration: try context suffix disambiguation - if iteration == 0 { - resolveWithContextSuffix(group, candidates) - continue - } - - // Subsequent iterations: existing disambiguateName logic - for i, s := range group { - newName := disambiguateName(s, candidates[s], i, converter) - candidates[s] = newName - } - } - } -} - -// resolveWithContextSuffix attempts to disambiguate colliding schemas by -// appending a suffix derived from their path context (e.g. "Request", -// "Response"). If exactly one member is a component schema, it keeps the -// bare name and only the others are suffixed. -func resolveWithContextSuffix(group []*SchemaDescriptor, candidates map[*SchemaDescriptor]string) { - // Count how many are from components/schemas - var componentSchemaCount int - for _, s := range group { - ctx, _ := parsePathContext(s.Path) - if ctx == ContextComponentSchema { - componentSchemaCount++ - } - } - - // If exactly one is from components/schemas, it is "privileged" and keeps - // the bare name. - privileged := componentSchemaCount == 1 - - for _, s := range group { - ctx, _ := parsePathContext(s.Path) - - // Privileged component schema keeps the bare name - if privileged && ctx == ContextComponentSchema { - continue - } - - suffix := schemaContextSuffix(ctx) - if suffix != "" { - name := candidates[s] - if !strings.HasSuffix(name, suffix) { - candidates[s] = name + suffix - } - } - // If suffix is empty (unknown context), leave unchanged for later - // iterations to handle via disambiguateName. - } -} - -// disambiguateName adds more context to make a name unique. -func disambiguateName(s *SchemaDescriptor, currentName string, index int, converter *NameConverter) string { - path := s.Path - - // Try to add more path context based on what's in the path - // but not already in the name - - // Check for content type differentiation - for i, part := range path { - if part == "content" && i+1 < len(path) { - contentType := path[i+1] - var suffix string - switch { - case strings.Contains(contentType, "json"): - suffix = "JSON" - case strings.Contains(contentType, "xml"): - suffix = "XML" - case strings.Contains(contentType, "form"): - suffix = "Form" - case strings.Contains(contentType, "text"): - suffix = "Text" - case strings.Contains(contentType, "binary"): - suffix = "Binary" - default: - suffix = converter.ToTypeName(strings.ReplaceAll(contentType, "/", "_")) - } - // Use Contains since the suffix might be embedded before "Response" or "Request" - if !strings.Contains(currentName, suffix) { - return currentName + suffix - } - } - } - - // Check for status code differentiation (for responses) - for i, part := range path { - if part == "responses" && i+1 < len(path) { - code := path[i+1] - if !strings.Contains(currentName, code) { - return currentName + code - } - } - } - - // Check for parameter index differentiation - for i, part := range path { - if part == "parameters" && i+1 < len(path) { - idx := path[i+1] - if !strings.HasSuffix(currentName, idx) { - return currentName + idx - } - } - } - - // Check for composition type differentiation - for i := len(path) - 1; i >= 0; i-- { - part := path[i] - switch part { - case "allOf", "anyOf", "oneOf": - suffix := converter.ToTypeName(part) - if i+1 < len(path) { - suffix += path[i+1] // Add index - } - if !strings.Contains(currentName, suffix) { - return currentName + suffix - } - } - } - - // Last resort: use numeric suffix - return fmt.Sprintf("%s%d", currentName, index+1) -} - -// buildOperationRequestName builds a name for a request body using the operationId. -// e.g., operationId="addPet" -> "AddPetJSONRequest" -func buildOperationRequestName(operationID, contentType string, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { - baseName := converter.ToTypeName(operationID) - - // Add content type short name if available - if contentType != "" && contentTypeNamer != nil { - baseName += contentTypeNamer.ShortName(contentType) - } - - return baseName + "Request" -} - -// buildOperationResponseName builds a name for a response using the operationId. -// e.g., operationId="findPets", statusCode="200" -> "FindPetsJSONResponse" -// e.g., operationId="findPets", statusCode="404" -> "FindPets404JSONResponse" -// e.g., operationId="findPets", statusCode="default" -> "FindPetsDefaultJSONResponse" -func buildOperationResponseName(operationID, statusCode, contentType string, converter *NameConverter, contentTypeNamer *ContentTypeShortNamer) string { - baseName := converter.ToTypeName(operationID) - - // Add status code, skipping only for 200 (the common success case) - if statusCode != "" && statusCode != "200" { - if statusCode == "default" { - baseName += "Default" - } else { - baseName += statusCode - } - } - - // Add content type short name if available - if contentType != "" && contentTypeNamer != nil { - baseName += contentTypeNamer.ShortName(contentType) - } - - return baseName + "Response" -} - -// extractStatusCode extracts the HTTP status code from path parts. -// Looks for "responses" followed by the status code. -func extractStatusCode(parts []string) string { - for i, p := range parts { - if p == "responses" && i+1 < len(parts) { - return parts[i+1] - } - } - return "" -} - -// isDirectBodySchema returns true if the schema path represents the direct -// schema of a request body or response (i.e., content/{type}/schema), -// not a nested schema (items, properties, allOf members, etc.). -func isDirectBodySchema(path SchemaPath) bool { - // Find the position of "schema" after "content" - schemaIdx := -1 - for i := len(path) - 1; i >= 0; i-- { - if path[i] == "schema" { - schemaIdx = i - break - } - } - if schemaIdx == -1 { - return false - } - - // Check that "schema" is directly after a content type (content/{type}/schema) - // and there are no structural elements after it - if schemaIdx < 2 { - return false - } - if path[schemaIdx-2] != "content" { - return false - } - - // If schema is at the end of the path, it's a direct body schema - return schemaIdx == len(path)-1 -} diff --git a/experimental/internal/codegen/servergen.go b/experimental/internal/codegen/servergen.go deleted file mode 100644 index 86177c4167..0000000000 --- a/experimental/internal/codegen/servergen.go +++ /dev/null @@ -1,180 +0,0 @@ -package codegen - -import ( - "bytes" - "fmt" - "text/template" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -// ServerGenerator generates server code from operation descriptors. -type ServerGenerator struct { - tmpl *template.Template - serverType string -} - -// NewServerGenerator creates a new server generator for the specified server type. -func NewServerGenerator(serverType string) (*ServerGenerator, error) { - if serverType == "" { - // No server generation requested - return &ServerGenerator{serverType: ""}, nil - } - - tmpl := template.New("server").Funcs(templates.Funcs()) - - // Get templates for the specified server type - serverTemplates, err := getServerTemplates(serverType) - if err != nil { - return nil, err - } - - // Parse server-specific templates - for _, st := range serverTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + st.Template) - if err != nil { - return nil, fmt.Errorf("failed to read template %s: %w", st.Template, err) - } - _, err = tmpl.New(st.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse template %s: %w", st.Template, err) - } - } - - // Parse shared templates - for _, st := range templates.SharedServerTemplates { - content, err := templates.TemplateFS.ReadFile("files/" + st.Template) - if err != nil { - return nil, fmt.Errorf("failed to read shared template %s: %w", st.Template, err) - } - _, err = tmpl.New(st.Name).Parse(string(content)) - if err != nil { - return nil, fmt.Errorf("failed to parse shared template %s: %w", st.Template, err) - } - } - - return &ServerGenerator{tmpl: tmpl, serverType: serverType}, nil -} - -// getServerTemplates returns the templates for the specified server type. -func getServerTemplates(serverType string) (map[string]templates.ServerTemplate, error) { - switch serverType { - case ServerTypeStdHTTP: - return templates.StdHTTPServerTemplates, nil - case ServerTypeChi: - return templates.ChiServerTemplates, nil - case ServerTypeEcho: - return templates.EchoServerTemplates, nil - case ServerTypeEchoV4: - return templates.EchoV4ServerTemplates, nil - case ServerTypeGin: - return templates.GinServerTemplates, nil - case ServerTypeGorilla: - return templates.GorillaServerTemplates, nil - case ServerTypeFiber: - return templates.FiberServerTemplates, nil - case ServerTypeIris: - return templates.IrisServerTemplates, nil - default: - return nil, fmt.Errorf("unsupported server type: %q (supported: %q, %q, %q, %q, %q, %q, %q, %q)", - serverType, - ServerTypeStdHTTP, ServerTypeChi, ServerTypeEcho, ServerTypeEchoV4, ServerTypeGin, - ServerTypeGorilla, ServerTypeFiber, ServerTypeIris) - } -} - -// GenerateInterface generates the ServerInterface. -func (g *ServerGenerator) GenerateInterface(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "interface", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateHandler generates the HTTP handler and routing code. -func (g *ServerGenerator) GenerateHandler(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "handler", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateWrapper generates the ServerInterfaceWrapper. -func (g *ServerGenerator) GenerateWrapper(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "wrapper", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateErrors generates the error types. -func (g *ServerGenerator) GenerateErrors() (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "errors", nil); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateParamTypes generates the parameter struct types. -func (g *ServerGenerator) GenerateParamTypes(ops []*OperationDescriptor) (string, error) { - var buf bytes.Buffer - if err := g.tmpl.ExecuteTemplate(&buf, "param_types", ops); err != nil { - return "", err - } - return buf.String(), nil -} - -// GenerateServer generates all server code components. -// Returns empty string if no server type was configured. -func (g *ServerGenerator) GenerateServer(ops []*OperationDescriptor) (string, error) { - if g.serverType == "" || g.tmpl == nil { - return "", nil - } - - var buf bytes.Buffer - - // Generate interface - iface, err := g.GenerateInterface(ops) - if err != nil { - return "", err - } - buf.WriteString(iface) - buf.WriteString("\n") - - // Generate param types - paramTypes, err := g.GenerateParamTypes(ops) - if err != nil { - return "", err - } - buf.WriteString(paramTypes) - buf.WriteString("\n") - - // Generate wrapper - wrapper, err := g.GenerateWrapper(ops) - if err != nil { - return "", err - } - buf.WriteString(wrapper) - buf.WriteString("\n") - - // Generate handler - handler, err := g.GenerateHandler(ops) - if err != nil { - return "", err - } - buf.WriteString(handler) - buf.WriteString("\n") - - // Generate errors - errors, err := g.GenerateErrors() - if err != nil { - return "", err - } - buf.WriteString(errors) - - return buf.String(), nil -} diff --git a/experimental/internal/codegen/skip_external_ref_test.go b/experimental/internal/codegen/skip_external_ref_test.go deleted file mode 100644 index 6983852a73..0000000000 --- a/experimental/internal/codegen/skip_external_ref_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package codegen - -import ( - "os" - "strings" - "testing" - - "github.com/pb33f/libopenapi" - "github.com/pb33f/libopenapi/datamodel" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// TestSkipExternalRefResolution verifies that we can parse a spec containing -// external $ref references without resolving them, and still generate correct -// code using import mappings. This uses libopenapi's SkipExternalRefResolution -// flag (added in v0.33.4, pb33f/libopenapi#519). -func TestSkipExternalRefResolution(t *testing.T) { - specData, err := os.ReadFile("test/external_ref/spec.yaml") - require.NoError(t, err) - - // Parse WITHOUT BasePath or AllowFileReferences — the external spec files - // won't be read. Instead, we rely on SkipExternalRefResolution to leave - // external $refs unresolved while still building an iterable model. - docConfig := datamodel.NewDocumentConfiguration() - docConfig.SkipExternalRefResolution = true - - doc, err := libopenapi.NewDocumentWithConfiguration(specData, docConfig) - require.NoError(t, err) - - cfg := Configuration{ - PackageName: "externalref", - ImportMapping: map[string]string{ - "./packagea/spec.yaml": "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea", - "./packageb/spec.yaml": "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb", - }, - } - - code, err := Generate(doc, nil, cfg) - require.NoError(t, err) - - // The generated code should contain the Container struct with external type references - assert.Contains(t, code, "type Container struct") - assert.Contains(t, code, "ObjectA") - assert.Contains(t, code, "ObjectB") - - // Should reference the external packages via hashed aliases - assert.Contains(t, code, "ext_95d82e90") - assert.Contains(t, code, "ext_a5fddf6c") - - // Should contain the import declarations - assert.Contains(t, code, `"github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea"`) - assert.Contains(t, code, `"github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb"`) - - // Should NOT contain "any" as a fallback type for the external refs - // (which would indicate the refs weren't properly detected) - lines := strings.Split(code, "\n") - for _, line := range lines { - if strings.Contains(line, "ObjectA") && strings.Contains(line, "any") { - t.Errorf("ObjectA resolved to 'any' instead of external type: %s", line) - } - if strings.Contains(line, "ObjectB") && strings.Contains(line, "any") { - t.Errorf("ObjectB resolved to 'any' instead of external type: %s", line) - } - } - - t.Logf("Generated code:\n%s", code) -} diff --git a/experimental/internal/codegen/structtags.go b/experimental/internal/codegen/structtags.go deleted file mode 100644 index 36279956b7..0000000000 --- a/experimental/internal/codegen/structtags.go +++ /dev/null @@ -1,172 +0,0 @@ -package codegen - -import ( - "bytes" - "sort" - "strings" - "text/template" -) - -// StructTagInfo contains the data available to struct tag templates. -type StructTagInfo struct { - // FieldName is the JSON/YAML field name (from the OpenAPI property name) - FieldName string - // GoFieldName is the Go struct field name - GoFieldName string - // IsOptional is true if the field is optional (not required) - IsOptional bool - // IsNullable is true if the field can be null - IsNullable bool - // IsPointer is true if the Go type is a pointer - IsPointer bool - // OmitEmpty is true if the omitempty tag option should be used - // (derived from IsOptional but can be overridden via extensions) - OmitEmpty bool - // OmitZero is true if the omitzero tag option should be used (Go 1.24+) - OmitZero bool - // JSONIgnore is true if the field should be excluded from JSON (json:"-") - JSONIgnore bool -} - -// StructTagTemplate defines a single struct tag with a name and template. -type StructTagTemplate struct { - // Name is the tag name (e.g., "json", "yaml", "form") - Name string `yaml:"name"` - // Template is a Go text/template that produces the tag value. - // Available fields: .FieldName, .GoFieldName, .IsOptional, .IsNullable, .IsPointer - // Example: `{{ .FieldName }}{{if .IsOptional}},omitempty{{end}}` - Template string `yaml:"template"` -} - -// StructTagsConfig configures struct tag generation. -type StructTagsConfig struct { - // Tags is the list of tags to generate for struct fields. - // Order is preserved in the generated output. - Tags []StructTagTemplate `yaml:"tags,omitempty"` -} - -// DefaultStructTagsConfig returns the default struct tag configuration. -// By default, json and form tags are generated. -func DefaultStructTagsConfig() StructTagsConfig { - return StructTagsConfig{ - Tags: []StructTagTemplate{ - { - Name: "json", - Template: `{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{if .OmitZero}},omitzero{{end}}{{end}}`, - }, - { - Name: "form", - Template: `{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{end}}`, - }, - }, - } -} - -// Merge merges user config on top of this config. -// If user specifies any tags, they completely replace the defaults. -func (c StructTagsConfig) Merge(other StructTagsConfig) StructTagsConfig { - if len(other.Tags) > 0 { - return other - } - return c -} - -// StructTagGenerator generates struct tags from templates. -type StructTagGenerator struct { - templates []*tagTemplate -} - -type tagTemplate struct { - name string - tmpl *template.Template -} - -// NewStructTagGenerator creates a generator from the configuration. -// Invalid templates are silently skipped. -func NewStructTagGenerator(config StructTagsConfig) *StructTagGenerator { - g := &StructTagGenerator{ - templates: make([]*tagTemplate, 0, len(config.Tags)), - } - - for _, tag := range config.Tags { - tmpl, err := template.New(tag.Name).Parse(tag.Template) - if err != nil { - // Skip invalid templates - continue - } - g.templates = append(g.templates, &tagTemplate{ - name: tag.Name, - tmpl: tmpl, - }) - } - - return g -} - -// GenerateTags generates the complete struct tag string for a field. -// Returns a string like `json:"name,omitempty" yaml:"name,omitempty"`. -func (g *StructTagGenerator) GenerateTags(info StructTagInfo) string { - if len(g.templates) == 0 { - return "" - } - - var tags []string - for _, t := range g.templates { - var buf bytes.Buffer - if err := t.tmpl.Execute(&buf, info); err != nil { - // Skip tags that fail to render - continue - } - value := buf.String() - if value != "" { - tags = append(tags, t.name+`:`+`"`+value+`"`) - } - } - - if len(tags) == 0 { - return "" - } - - return "`" + strings.Join(tags, " ") + "`" -} - -// GenerateTagsMap generates tags as a map for cases where we need to add extra tags. -// Returns a map of tag name -> tag value (without quotes). -func (g *StructTagGenerator) GenerateTagsMap(info StructTagInfo) map[string]string { - result := make(map[string]string) - - for _, t := range g.templates { - var buf bytes.Buffer - if err := t.tmpl.Execute(&buf, info); err != nil { - continue - } - value := buf.String() - if value != "" { - result[t.name] = value - } - } - - return result -} - -// FormatTagsMap formats a tag map into a struct tag string. -// Tags are sorted alphabetically by name for deterministic output. -func FormatTagsMap(tags map[string]string) string { - if len(tags) == 0 { - return "" - } - - // Sort tag names for deterministic output - names := make([]string, 0, len(tags)) - for name := range tags { - names = append(names, name) - } - sort.Strings(names) - - var parts []string - for _, name := range names { - parts = append(parts, name+`:`+`"`+tags[name]+`"`) - } - - return "`" + strings.Join(parts, " ") + "`" -} diff --git a/experimental/internal/codegen/templates/embed.go b/experimental/internal/codegen/templates/embed.go deleted file mode 100644 index ed91bb95e7..0000000000 --- a/experimental/internal/codegen/templates/embed.go +++ /dev/null @@ -1,9 +0,0 @@ -package templates - -import "embed" - -// TemplateFS contains all embedded template files. -// The files/* pattern recursively includes all files in subdirectories. -// -//go:embed files/* -var TemplateFS embed.FS diff --git a/experimental/internal/codegen/templates/files/client/base.go.tmpl b/experimental/internal/codegen/templates/files/client/base.go.tmpl deleted file mode 100644 index 96d32997f4..0000000000 --- a/experimental/internal/codegen/templates/files/client/base.go.tmpl +++ /dev/null @@ -1,95 +0,0 @@ -{{/* Base client template - returns raw *http.Response */}} - -// RequestEditorFn is the function signature for the RequestEditor callback function. -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// HttpRequestDoer 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 - -// NewClient creates a new Client with reasonable defaults. -func NewClient(server string, opts ...ClientOption) (*Client, error) { - client := Client{ - Server: server, - } - 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 - } -} - -// 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 - } -} - -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 -} diff --git a/experimental/internal/codegen/templates/files/client/interface.go.tmpl b/experimental/internal/codegen/templates/files/client/interface.go.tmpl deleted file mode 100644 index 458e4867dc..0000000000 --- a/experimental/internal/codegen/templates/files/client/interface.go.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -{{/* Client interface template */}} - -// ClientInterface is the interface specification for the client. -type ClientInterface interface { -{{- range . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $pathParams := .PathParams }} - // {{ $opid }}{{ if .HasBody }}WithBody{{ end }} makes a {{ .Method }} request to {{ .Path }} - {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ .ParamsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) -{{- range .Bodies }} -{{- if .IsJSON }} - {{ $opid }}{{ .FuncSuffix }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $.ParamsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) -{{- end }} -{{- end }} -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/client/methods.go.tmpl b/experimental/internal/codegen/templates/files/client/methods.go.tmpl deleted file mode 100644 index a7a6dfd7f1..0000000000 --- a/experimental/internal/codegen/templates/files/client/methods.go.tmpl +++ /dev/null @@ -1,40 +0,0 @@ -{{/* Client methods template - implements ClientInterface */}} - -{{- range . }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $pathParams := .PathParams }} -{{- $paramsTypeName := .ParamsTypeName }} - -// {{ $opid }}{{ if .HasBody }}WithBody{{ end }} makes a {{ .Method }} request to {{ .Path }} -{{ if .Summary }}// {{ .Summary }}{{ end }} -func (c *Client) {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }}(c.Server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}{{ if .HasBody }}, contentType, body{{ end }}) - 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) -} -{{- range .Bodies }} -{{- if .IsJSON }} - -// {{ $opid }}{{ .FuncSuffix }} makes a {{ $op.Method }} request to {{ $op.Path }} with JSON body -func (c *Client) {{ $opid }}{{ .FuncSuffix }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := New{{ $opid }}Request{{ .FuncSuffix }}(c.Server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, 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) -} -{{- end }} -{{- end }} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl b/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl deleted file mode 100644 index 6461c14de9..0000000000 --- a/experimental/internal/codegen/templates/files/client/request_builders.go.tmpl +++ /dev/null @@ -1,177 +0,0 @@ -{{/* Request builder functions template */}} - -{{- range . }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $pathParams := .PathParams }} -{{- $paramsTypeName := .ParamsTypeName }} -{{- $queryParams := .QueryParams }} -{{- $headerParams := .HeaderParams }} -{{- $cookieParams := .CookieParams }} - -{{- /* Generate typed body request builders for JSON bodies */ -}} -{{- range .Bodies }} -{{- if .IsJSON }} - -// New{{ $opid }}Request{{ .FuncSuffix }} creates a {{ $op.Method }} request for {{ $op.Path }} with {{ .ContentType }} body -func New{{ $opid }}Request{{ .FuncSuffix }}(server string{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return New{{ $opid }}RequestWithBody(server{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, "{{ .ContentType }}", bodyReader) -} -{{- end }} -{{- end }} - -// New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }} creates a {{ .Method }} request for {{ .Path }}{{ if .HasBody }} with any body{{ end }} -func New{{ $opid }}Request{{ if .HasBody }}WithBody{{ end }}(server string{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}) (*http.Request, error) { - var err error -{{- range $idx, $param := $pathParams }} - - var pathParam{{ $idx }} string - {{- if .IsPassThrough }} - pathParam{{ $idx }} = {{ .GoVariableName }} - {{- else if .IsJSON }} - var pathParamBuf{{ $idx }} []byte - pathParamBuf{{ $idx }}, err = json.Marshal({{ .GoVariableName }}) - if err != nil { - return nil, err - } - pathParam{{ $idx }} = string(pathParamBuf{{ $idx }}) - {{- else if .IsStyled }} - pathParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationPath, {{ .GoVariableName }}) - if err != nil { - return nil, err - } - {{- end }} -{{- end }} - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("{{ pathFmt .Path }}"{{ range $idx, $_ := $pathParams }}, pathParam{{ $idx }}{{ end }}) - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } -{{- if $queryParams }} - - if params != nil { - queryValues := queryURL.Query() -{{- range $idx, $param := $queryParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - {{- if .IsPassThrough }} - queryValues.Add("{{ .Name }}", {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - {{- else if .IsJSON }} - if queryParamBuf, err := json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); err != nil { - return nil, err - } else { - queryValues.Add("{{ .Name }}", string(queryParamBuf)) - } - {{- else if .IsStyled }} - if queryFrag, err := {{ .StyleFunc }}("{{ .Name }}", ParamLocationQuery, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); 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) - } - } - } - {{- end }} - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - queryURL.RawQuery = queryValues.Encode() - } -{{- end }} - - req, err := http.NewRequest("{{ .Method }}", queryURL.String(), {{ if .HasBody }}body{{ else }}nil{{ end }}) - if err != nil { - return nil, err - } - - {{ if .HasBody }}req.Header.Add("Content-Type", contentType){{ end }} -{{- if $headerParams }} - - if params != nil { -{{- range $idx, $param := $headerParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - var headerParam{{ $idx }} string - {{- if .IsPassThrough }} - headerParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} - {{- else if .IsJSON }} - var headerParamBuf{{ $idx }} []byte - headerParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - headerParam{{ $idx }} = string(headerParamBuf{{ $idx }}) - {{- else if .IsStyled }} - headerParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationHeader, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - {{- end }} - req.Header.Set("{{ .Name }}", headerParam{{ $idx }}) - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - } -{{- end }} -{{- if $cookieParams }} - - if params != nil { -{{- range $idx, $param := $cookieParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - var cookieParam{{ $idx }} string - {{- if .IsPassThrough }} - cookieParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} - {{- else if .IsJSON }} - var cookieParamBuf{{ $idx }} []byte - cookieParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - cookieParam{{ $idx }} = url.QueryEscape(string(cookieParamBuf{{ $idx }})) - {{- else if .IsStyled }} - cookieParam{{ $idx }}, err = StyleSimpleParam("{{ .Name }}", ParamLocationCookie, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - {{- end }} - cookie{{ $idx }} := &http.Cookie{ - Name: "{{ .Name }}", - Value: cookieParam{{ $idx }}, - } - req.AddCookie(cookie{{ $idx }}) - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - } -{{- end }} - - return req, nil -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/client/simple.go.tmpl b/experimental/internal/codegen/templates/files/client/simple.go.tmpl deleted file mode 100644 index 988cf73182..0000000000 --- a/experimental/internal/codegen/templates/files/client/simple.go.tmpl +++ /dev/null @@ -1,121 +0,0 @@ -{{/* SimpleClient template - wraps Client with typed responses for simple operations */}} - -// ClientHttpError represents an HTTP error response from the server. -// The type parameter E is the type of the parsed error body. -type ClientHttpError[E any] struct { - StatusCode int - Body E - RawBody []byte -} - -func (e *ClientHttpError[E]) Error() string { - return fmt.Sprintf("HTTP %d", e.StatusCode) -} - -// SimpleClient wraps Client with typed responses for operations that have -// unambiguous response types. Methods return the success type directly, -// and HTTP errors are returned as *ClientHttpError[E] where E is the error type. -type SimpleClient struct { - *Client -} - -// NewSimpleClient creates a new SimpleClient which wraps a Client. -func NewSimpleClient(server string, opts ...ClientOption) (*SimpleClient, error) { - client, err := NewClient(server, opts...) - if err != nil { - return nil, err - } - return &SimpleClient{Client: client}, nil -} - -{{- range . }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $pathParams := .PathParams }} -{{- $paramsTypeName := .ParamsTypeName }} - -{{- /* Determine if this operation is "simple" - single success content type, single JSON success response */}} -{{- $simpleOp := isSimpleOperation . }} -{{- if $simpleOp }} -{{- $successResponse := simpleOperationSuccessResponse . }} -{{- $successContent := index $successResponse.Contents 0 }} -{{- $successType := goTypeForContent $successContent }} -{{- $errorResponse := errorResponseForOperation . }} - -// {{ $opid }} makes a {{ .Method }} request to {{ .Path }} and returns the parsed response. -{{ if .Summary }}// {{ .Summary }}{{ end }} -{{- if $errorResponse }} -{{- $errorContent := index $errorResponse.Contents 0 }} -{{- $errorType := goTypeForContent $errorContent }} -// On success, returns the response body. On HTTP error, returns *ClientHttpError[{{ $errorType }}]. -func (c *SimpleClient) {{ $opid }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { - var result {{ $successType }} -{{- if .HasBody }} -{{- $defaultBody := index .Bodies 0 }} - resp, err := c.Client.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, body, reqEditors...) -{{- else }} - resp, err := c.Client.{{ $opid }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, reqEditors...) -{{- end }} - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // Parse error response - var errBody {{ $errorType }} - _ = json.Unmarshal(rawBody, &errBody) // Best effort parse - return result, &ClientHttpError[{{ $errorType }}]{ - StatusCode: resp.StatusCode, - Body: errBody, - RawBody: rawBody, - } -} -{{- else }} -// On success, returns the response body. On HTTP error, returns *ClientHttpError[struct{}]. -func (c *SimpleClient) {{ $opid }}(ctx context.Context{{ range $pathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { - var result {{ $successType }} -{{- if .HasBody }} -{{- $defaultBody := index .Bodies 0 }} - resp, err := c.Client.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, body, reqEditors...) -{{- else }} - resp, err := c.Client.{{ $opid }}(ctx{{ range $pathParams }}, {{ .GoVariableName }}{{ end }}{{ if $hasParams }}, params{{ end }}, reqEditors...) -{{- end }} - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // No typed error response defined - return result, &ClientHttpError[struct{}]{ - StatusCode: resp.StatusCode, - RawBody: rawBody, - } -} -{{- end }} -{{- end }} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/base.go.tmpl b/experimental/internal/codegen/templates/files/initiator/base.go.tmpl deleted file mode 100644 index 99e885136d..0000000000 --- a/experimental/internal/codegen/templates/files/initiator/base.go.tmpl +++ /dev/null @@ -1,73 +0,0 @@ -{{/* Initiator base template - framework-agnostic HTTP client for webhooks/callbacks */}} -{{/* Input: InitiatorTemplateData */}} - -// RequestEditorFn is the function signature for the RequestEditor callback function. -// It may already be defined if client code is also generated; this is a compatible redeclaration. -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// HttpRequestDoer performs HTTP requests. -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// {{ .Prefix }}Initiator sends {{ .PrefixLower }} requests to target URLs. -// Unlike Client, it has no stored base URL — the full target URL is provided per-call. -type {{ .Prefix }}Initiator struct { - // 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 -} - -// {{ .Prefix }}InitiatorOption allows setting custom parameters during construction. -type {{ .Prefix }}InitiatorOption func(*{{ .Prefix }}Initiator) error - -// New{{ .Prefix }}Initiator creates a new {{ .Prefix }}Initiator with reasonable defaults. -func New{{ .Prefix }}Initiator(opts ...{{ .Prefix }}InitiatorOption) (*{{ .Prefix }}Initiator, error) { - initiator := {{ .Prefix }}Initiator{} - for _, o := range opts { - if err := o(&initiator); err != nil { - return nil, err - } - } - if initiator.Client == nil { - initiator.Client = &http.Client{} - } - return &initiator, nil -} - -// With{{ .Prefix }}HTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func With{{ .Prefix }}HTTPClient(doer HttpRequestDoer) {{ .Prefix }}InitiatorOption { - return func(p *{{ .Prefix }}Initiator) error { - p.Client = doer - return nil - } -} - -// With{{ .Prefix }}RequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func With{{ .Prefix }}RequestEditorFn(fn RequestEditorFn) {{ .Prefix }}InitiatorOption { - return func(p *{{ .Prefix }}Initiator) error { - p.RequestEditors = append(p.RequestEditors, fn) - return nil - } -} - -func (p *{{ .Prefix }}Initiator) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range p.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 -} diff --git a/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl b/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl deleted file mode 100644 index a6ad431733..0000000000 --- a/experimental/internal/codegen/templates/files/initiator/interface.go.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -{{/* Initiator interface template */}} -{{/* Input: InitiatorTemplateData */}} - -// {{ .Prefix }}InitiatorInterface is the interface specification for the {{ .PrefixLower }} initiator. -type {{ .Prefix }}InitiatorInterface interface { -{{- range .Operations }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} - // {{ $opid }}{{ if .HasBody }}WithBody{{ end }} sends a {{ .Method }} {{ $.PrefixLower }} request - {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ .ParamsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) -{{- range .Bodies }} -{{- if .IsJSON }} - {{ $opid }}{{ .FuncSuffix }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $.ParamsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) -{{- end }} -{{- end }} -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl b/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl deleted file mode 100644 index ff079042ed..0000000000 --- a/experimental/internal/codegen/templates/files/initiator/methods.go.tmpl +++ /dev/null @@ -1,41 +0,0 @@ -{{/* Initiator methods template - implements InitiatorInterface */}} -{{/* Input: InitiatorTemplateData */}} - -{{- range .Operations }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $paramsTypeName := .ParamsTypeName }} -{{- $prefix := $.Prefix }} - -// {{ $opid }}{{ if .HasBody }}WithBody{{ end }} sends a {{ .Method }} {{ $.PrefixLower }} request -{{ if .Summary }}// {{ .Summary }}{{ end }} -func (p *{{ $prefix }}Initiator) {{ $opid }}{{ if .HasBody }}WithBody{{ end }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := New{{ $opid }}{{ $.Prefix }}Request{{ if .HasBody }}WithBody{{ end }}(targetURL{{ if $hasParams }}, params{{ end }}{{ if .HasBody }}, contentType, body{{ end }}) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} -{{- range .Bodies }} -{{- if .IsJSON }} - -// {{ $opid }}{{ .FuncSuffix }} sends a {{ $op.Method }} {{ $.PrefixLower }} request with JSON body -func (p *{{ $prefix }}Initiator) {{ $opid }}{{ .FuncSuffix }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }}(targetURL{{ if $hasParams }}, params{{ end }}, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := p.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return p.Client.Do(req) -} -{{- end }} -{{- end }} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl b/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl deleted file mode 100644 index d651403492..0000000000 --- a/experimental/internal/codegen/templates/files/initiator/request_builders.go.tmpl +++ /dev/null @@ -1,149 +0,0 @@ -{{/* Initiator request builder functions template */}} -{{/* Input: InitiatorTemplateData */}} - -{{- range .Operations }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $paramsTypeName := .ParamsTypeName }} -{{- $queryParams := .QueryParams }} -{{- $headerParams := .HeaderParams }} -{{- $cookieParams := .CookieParams }} -{{- $prefix := $.Prefix }} - -{{- /* Generate typed body request builders for JSON bodies */ -}} -{{- range .Bodies }} -{{- if .IsJSON }} - -// New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }} creates a {{ $op.Method }} request for the {{ $.PrefixLower }} with {{ .ContentType }} body -func New{{ $opid }}{{ $prefix }}Request{{ .FuncSuffix }}(targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}, body {{ .GoTypeName }}) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return New{{ $opid }}{{ $prefix }}RequestWithBody(targetURL{{ if $hasParams }}, params{{ end }}, "{{ .ContentType }}", bodyReader) -} -{{- end }} -{{- end }} - -// New{{ $opid }}{{ $prefix }}Request{{ if .HasBody }}WithBody{{ end }} creates a {{ .Method }} request for the {{ $.PrefixLower }}{{ if .HasBody }} with any body{{ end }} -func New{{ $opid }}{{ $prefix }}Request{{ if .HasBody }}WithBody{{ end }}(targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, contentType string, body io.Reader{{ end }}) (*http.Request, error) { - var err error - - parsedURL, err := url.Parse(targetURL) - if err != nil { - return nil, err - } -{{- if $queryParams }} - - if params != nil { - queryValues := parsedURL.Query() -{{- range $idx, $param := $queryParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - {{- if .IsPassThrough }} - queryValues.Add("{{ .Name }}", {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - {{- else if .IsJSON }} - if queryParamBuf, err := json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); err != nil { - return nil, err - } else { - queryValues.Add("{{ .Name }}", string(queryParamBuf)) - } - {{- else if .IsStyled }} - if queryFrag, err := {{ .StyleFunc }}("{{ .Name }}", ParamLocationQuery, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}); 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) - } - } - } - {{- end }} - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - parsedURL.RawQuery = queryValues.Encode() - } -{{- end }} - - req, err := http.NewRequest("{{ .Method }}", parsedURL.String(), {{ if .HasBody }}body{{ else }}nil{{ end }}) - if err != nil { - return nil, err - } - - {{ if .HasBody }}req.Header.Add("Content-Type", contentType){{ end }} -{{- if $headerParams }} - - if params != nil { -{{- range $idx, $param := $headerParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - var headerParam{{ $idx }} string - {{- if .IsPassThrough }} - headerParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} - {{- else if .IsJSON }} - var headerParamBuf{{ $idx }} []byte - headerParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - headerParam{{ $idx }} = string(headerParamBuf{{ $idx }}) - {{- else if .IsStyled }} - headerParam{{ $idx }}, err = {{ .StyleFunc }}("{{ .Name }}", ParamLocationHeader, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - {{- end }} - req.Header.Set("{{ .Name }}", headerParam{{ $idx }}) - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - } -{{- end }} -{{- if $cookieParams }} - - if params != nil { -{{- range $idx, $param := $cookieParams }} - {{- if .HasOptionalPointer }} - if params.{{ .GoName }} != nil { - {{- end }} - var cookieParam{{ $idx }} string - {{- if .IsPassThrough }} - cookieParam{{ $idx }} = {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }} - {{- else if .IsJSON }} - var cookieParamBuf{{ $idx }} []byte - cookieParamBuf{{ $idx }}, err = json.Marshal({{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - cookieParam{{ $idx }} = url.QueryEscape(string(cookieParamBuf{{ $idx }})) - {{- else if .IsStyled }} - cookieParam{{ $idx }}, err = StyleSimpleParam("{{ .Name }}", ParamLocationCookie, {{ if .HasOptionalPointer }}*{{ end }}params.{{ .GoName }}) - if err != nil { - return nil, err - } - {{- end }} - cookie{{ $idx }} := &http.Cookie{ - Name: "{{ .Name }}", - Value: cookieParam{{ $idx }}, - } - req.AddCookie(cookie{{ $idx }}) - {{- if .HasOptionalPointer }} - } - {{- end }} -{{- end }} - } -{{- end }} - - return req, nil -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl b/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl deleted file mode 100644 index 008d4095ec..0000000000 --- a/experimental/internal/codegen/templates/files/initiator/simple.go.tmpl +++ /dev/null @@ -1,121 +0,0 @@ -{{/* Simple initiator template - wraps Initiator with typed responses for simple operations */}} -{{/* Input: InitiatorTemplateData */}} - -// {{ .Prefix }}HttpError represents an HTTP error response. -// The type parameter E is the type of the parsed error body. -type {{ .Prefix }}HttpError[E any] struct { - StatusCode int - Body E - RawBody []byte -} - -func (e *{{ .Prefix }}HttpError[E]) Error() string { - return fmt.Sprintf("HTTP %d", e.StatusCode) -} - -// Simple{{ .Prefix }}Initiator wraps {{ .Prefix }}Initiator with typed responses for operations that have -// unambiguous response types. Methods return the success type directly, -// and HTTP errors are returned as *{{ .Prefix }}HttpError[E] where E is the error type. -type Simple{{ .Prefix }}Initiator struct { - *{{ .Prefix }}Initiator -} - -// NewSimple{{ .Prefix }}Initiator creates a new Simple{{ .Prefix }}Initiator which wraps a {{ .Prefix }}Initiator. -func NewSimple{{ .Prefix }}Initiator(opts ...{{ .Prefix }}InitiatorOption) (*Simple{{ .Prefix }}Initiator, error) { - initiator, err := New{{ .Prefix }}Initiator(opts...) - if err != nil { - return nil, err - } - return &Simple{{ .Prefix }}Initiator{ {{ .Prefix }}Initiator: initiator}, nil -} - -{{- range .Operations }} -{{- $op := . }} -{{- $opid := .GoOperationID }} -{{- $hasParams := .HasParams }} -{{- $paramsTypeName := .ParamsTypeName }} - -{{- /* Determine if this operation is "simple" - single success content type, single JSON success response */}} -{{- $simpleOp := isSimpleOperation . }} -{{- if $simpleOp }} -{{- $successResponse := simpleOperationSuccessResponse . }} -{{- $successContent := index $successResponse.Contents 0 }} -{{- $successType := goTypeForContent $successContent }} -{{- $errorResponse := errorResponseForOperation . }} - -// {{ $opid }} sends a {{ .Method }} {{ $.PrefixLower }} request and returns the parsed response. -{{ if .Summary }}// {{ .Summary }}{{ end }} -{{- if $errorResponse }} -{{- $errorContent := index $errorResponse.Contents 0 }} -{{- $errorType := goTypeForContent $errorContent }} -// On success, returns the response body. On HTTP error, returns *{{ $.Prefix }}HttpError[{{ $errorType }}]. -func (p *Simple{{ $.Prefix }}Initiator) {{ $opid }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { - var result {{ $successType }} -{{- if .HasBody }} -{{- $defaultBody := index .Bodies 0 }} - resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, body, reqEditors...) -{{- else }} - resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, reqEditors...) -{{- end }} - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // Parse error response - var errBody {{ $errorType }} - _ = json.Unmarshal(rawBody, &errBody) // Best effort parse - return result, &{{ $.Prefix }}HttpError[{{ $errorType }}]{ - StatusCode: resp.StatusCode, - Body: errBody, - RawBody: rawBody, - } -} -{{- else }} -// On success, returns the response body. On HTTP error, returns *{{ $.Prefix }}HttpError[struct{}]. -func (p *Simple{{ $.Prefix }}Initiator) {{ $opid }}(ctx context.Context, targetURL string{{ if $hasParams }}, params *{{ $paramsTypeName }}{{ end }}{{ if .HasBody }}, body {{ (index .Bodies 0).GoTypeName }}{{ end }}, reqEditors ...RequestEditorFn) ({{ $successType }}, error) { - var result {{ $successType }} -{{- if .HasBody }} -{{- $defaultBody := index .Bodies 0 }} - resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}{{ $defaultBody.FuncSuffix }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, body, reqEditors...) -{{- else }} - resp, err := p.{{ $.Prefix }}Initiator.{{ $opid }}(ctx, targetURL{{ if $hasParams }}, params{{ end }}, reqEditors...) -{{- end }} - if err != nil { - return result, err - } - defer resp.Body.Close() - - rawBody, err := io.ReadAll(resp.Body) - if err != nil { - return result, err - } - - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - if err := json.Unmarshal(rawBody, &result); err != nil { - return result, err - } - return result, nil - } - - // No typed error response defined - return result, &{{ $.Prefix }}HttpError[struct{}]{ - StatusCode: resp.StatusCode, - RawBody: rawBody, - } -} -{{- end }} -{{- end }} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl deleted file mode 100644 index 403eb5c13d..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_deep_object.go.tmpl +++ /dev/null @@ -1,271 +0,0 @@ -{{/* BindDeepObjectParam - deepObject style (always exploded) */}} - -// BindDeepObjectParam binds a deepObject-style parameter to a destination. -// DeepObject style is only valid for query parameters and must be exploded. -// Objects: ?paramName[key1]=value1¶mName[key2]=value2 -> struct{Key1, Key2} -// Nested: ?paramName[outer][inner]=value -> struct{Outer: {Inner: value}} -func BindDeepObjectParam(paramName string, queryParams url.Values, dest interface{}) error { - return UnmarshalDeepObject(dest, paramName, queryParams) -} - -// UnmarshalDeepObject unmarshals deepObject-style query parameters to a destination. -func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error { - // Find all params that look like "paramName[..." - var fieldNames []string - var fieldValues []string - searchStr := paramName + "[" - - for pName, pValues := range params { - if strings.HasPrefix(pName, searchStr) { - // Trim the parameter name prefix - pName = pName[len(paramName):] - fieldNames = append(fieldNames, pName) - if len(pValues) != 1 { - return fmt.Errorf("%s has multiple values", pName) - } - fieldValues = append(fieldValues, pValues[0]) - } - } - - // Reconstruct subscript paths - paths := make([][]string, len(fieldNames)) - for i, path := range fieldNames { - path = strings.TrimLeft(path, "[") - path = strings.TrimRight(path, "]") - paths[i] = strings.Split(path, "][") - } - - fieldPaths := makeFieldOrValue(paths, fieldValues) - return assignPathValues(dst, fieldPaths) -} - -type fieldOrValue struct { - fields map[string]fieldOrValue - value string -} - -func (f *fieldOrValue) appendPathValue(path []string, value string) { - fieldName := path[0] - if len(path) == 1 { - f.fields[fieldName] = fieldOrValue{value: value} - return - } - - pv, found := f.fields[fieldName] - if !found { - pv = fieldOrValue{ - fields: make(map[string]fieldOrValue), - } - f.fields[fieldName] = pv - } - pv.appendPathValue(path[1:], value) -} - -func makeFieldOrValue(paths [][]string, values []string) fieldOrValue { - f := fieldOrValue{ - fields: make(map[string]fieldOrValue), - } - for i := range paths { - f.appendPathValue(paths[i], values[i]) - } - return f -} - -func getFieldName(f reflect.StructField) string { - n := f.Name - tag, found := f.Tag.Lookup("json") - if found { - parts := strings.Split(tag, ",") - if parts[0] != "" { - n = parts[0] - } - } - return n -} - -func fieldIndicesByJsonTag(i interface{}) (map[string]int, error) { - t := reflect.TypeOf(i) - if t.Kind() != reflect.Struct { - return nil, errors.New("expected a struct as input") - } - - n := t.NumField() - fieldMap := make(map[string]int) - for i := 0; i < n; i++ { - field := t.Field(i) - fieldName := getFieldName(field) - fieldMap[fieldName] = i - } - return fieldMap, nil -} - -func assignPathValues(dst interface{}, pathValues fieldOrValue) error { - v := reflect.ValueOf(dst) - iv := reflect.Indirect(v) - it := iv.Type() - - switch it.Kind() { - case reflect.Map: - dstMap := reflect.MakeMap(iv.Type()) - for key, value := range pathValues.fields { - dstKey := reflect.ValueOf(key) - dstVal := reflect.New(iv.Type().Elem()) - err := assignPathValues(dstVal.Interface(), value) - if err != nil { - return fmt.Errorf("error binding map: %w", err) - } - dstMap.SetMapIndex(dstKey, dstVal.Elem()) - } - iv.Set(dstMap) - return nil - - case reflect.Slice: - sliceLength := len(pathValues.fields) - dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength) - err := assignDeepObjectSlice(dstSlice, pathValues) - if err != nil { - return fmt.Errorf("error assigning slice: %w", err) - } - iv.Set(dstSlice) - return nil - - case reflect.Struct: - // Check for Binder interface - if dst, isBinder := v.Interface().(Binder); isBinder { - return dst.Bind(pathValues.value) - } - - // Handle Date type - if it.ConvertibleTo(reflect.TypeOf(Date{})) { - var date Date - var err error - date.Time, err = time.Parse(DateFormat, pathValues.value) - if err != nil { - return fmt.Errorf("invalid date format: %w", err) - } - dst := iv - if it != reflect.TypeOf(Date{}) { - ivPtr := iv.Addr() - aPtr := ivPtr.Convert(reflect.TypeOf(&Date{})) - dst = reflect.Indirect(aPtr) - } - dst.Set(reflect.ValueOf(date)) - return nil - } - - // Handle time.Time type - if it.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tm, err := time.Parse(time.RFC3339Nano, pathValues.value) - if err != nil { - tm, err = time.Parse(DateFormat, pathValues.value) - if err != nil { - return fmt.Errorf("error parsing '%s' as RFC3339 or date: %w", pathValues.value, err) - } - } - dst := iv - if it != reflect.TypeOf(time.Time{}) { - ivPtr := iv.Addr() - aPtr := ivPtr.Convert(reflect.TypeOf(&time.Time{})) - dst = reflect.Indirect(aPtr) - } - dst.Set(reflect.ValueOf(tm)) - return nil - } - - // Regular struct - fieldMap, err := fieldIndicesByJsonTag(iv.Interface()) - if err != nil { - return fmt.Errorf("failed enumerating fields: %w", err) - } - for _, fieldName := range sortedFieldOrValueKeys(pathValues.fields) { - fieldValue := pathValues.fields[fieldName] - fieldIndex, found := fieldMap[fieldName] - if !found { - return fmt.Errorf("field [%s] is not present in destination object", fieldName) - } - field := iv.Field(fieldIndex) - err = assignPathValues(field.Addr().Interface(), fieldValue) - if err != nil { - return fmt.Errorf("error assigning field [%s]: %w", fieldName, err) - } - } - return nil - - case reflect.Ptr: - dstVal := reflect.New(it.Elem()) - dstPtr := dstVal.Interface() - err := assignPathValues(dstPtr, pathValues) - iv.Set(dstVal) - return err - - case reflect.Bool: - val, err := strconv.ParseBool(pathValues.value) - if err != nil { - return fmt.Errorf("expected a valid bool, got %s", pathValues.value) - } - iv.SetBool(val) - return nil - - case reflect.Float32: - val, err := strconv.ParseFloat(pathValues.value, 32) - if err != nil { - return fmt.Errorf("expected a valid float, got %s", pathValues.value) - } - iv.SetFloat(val) - return nil - - case reflect.Float64: - val, err := strconv.ParseFloat(pathValues.value, 64) - if err != nil { - return fmt.Errorf("expected a valid float, got %s", pathValues.value) - } - iv.SetFloat(val) - return nil - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - val, err := strconv.ParseInt(pathValues.value, 10, 64) - if err != nil { - return fmt.Errorf("expected a valid int, got %s", pathValues.value) - } - iv.SetInt(val) - return nil - - case reflect.String: - iv.SetString(pathValues.value) - return nil - - default: - return errors.New("unhandled type: " + it.String()) - } -} - -func assignDeepObjectSlice(dst reflect.Value, pathValues fieldOrValue) error { - nValues := len(pathValues.fields) - values := make([]string, nValues) - for i := 0; i < nValues; i++ { - indexStr := strconv.Itoa(i) - fv, found := pathValues.fields[indexStr] - if !found { - return errors.New("array deepObjects must have consecutive indices") - } - values[i] = fv.value - } - - for i := 0; i < nValues; i++ { - dstElem := dst.Index(i).Addr() - err := assignPathValues(dstElem.Interface(), fieldOrValue{value: values[i]}) - if err != nil { - return fmt.Errorf("error binding array: %w", err) - } - } - return nil -} - -func sortedFieldOrValueKeys(m map[string]fieldOrValue) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} diff --git a/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl deleted file mode 100644 index 6b6b6d63de..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_form.go.tmpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* BindFormParam - form style without explode */}} - -// BindFormParam binds a form-style parameter without explode to a destination. -// Form style is the default for query and cookie parameters. -// This function handles a single query parameter value (not url.Values). -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindFormParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl deleted file mode 100644 index ec0f66d692..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_form_explode.go.tmpl +++ /dev/null @@ -1,145 +0,0 @@ -{{/* BindFormExplodeParam - form style with explode */}} - -// BindFormExplodeParam binds a form-style parameter with explode to a destination. -// Form style is the default for query and cookie parameters. -// This handles the exploded case where arrays come as multiple query params. -// Arrays: ?param=a¶m=b -> []string{"a", "b"} (values passed as slice) -// Objects: ?key1=value1&key2=value2 -> struct{Key1, Key2} (queryParams passed) -func BindFormExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - dv := reflect.Indirect(reflect.ValueOf(dest)) - v := dv - var output interface{} - - if required { - output = dest - } else { - // For optional parameters, allocate if nil - if v.IsNil() { - t := v.Type() - newValue := reflect.New(t.Elem()) - output = newValue.Interface() - } else { - output = v.Interface() - } - v = reflect.Indirect(reflect.ValueOf(output)) - } - - t := v.Type() - k := t.Kind() - - values, found := queryParams[paramName] - - switch k { - case reflect.Slice: - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := bindSplitPartsToDestinationArray(values, output) - if err != nil { - return err - } - case reflect.Struct: - // For exploded objects, fields are spread across query params - fieldsPresent, err := bindParamsToExplodedObject(paramName, queryParams, output) - if err != nil { - return err - } - if !fieldsPresent { - return nil - } - default: - // Primitive - if len(values) == 0 { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - if len(values) != 1 { - return fmt.Errorf("multiple values for single value parameter '%s'", paramName) - } - if !found { - if required { - return fmt.Errorf("query parameter '%s' is required", paramName) - } - return nil - } - err := BindStringToObject(values[0], output) - if err != nil { - return err - } - } - - if !required { - dv.Set(reflect.ValueOf(output)) - } - return nil -} - -// bindParamsToExplodedObject binds query params to struct fields for exploded objects. -func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) { - binder, v, t := indirectBinder(dest) - if binder != nil { - _, found := values[paramName] - if !found { - return false, nil - } - return true, BindStringToObject(values.Get(paramName), dest) - } - if t.Kind() != reflect.Struct { - return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName) - } - - fieldsPresent := false - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - if !v.Field(i).CanSet() { - continue - } - - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - - fieldVal, found := values[fieldName] - if found { - if len(fieldVal) != 1 { - return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName) - } - err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface()) - if err != nil { - return false, fmt.Errorf("could not bind query arg '%s': %w", paramName, err) - } - fieldsPresent = true - } - } - return fieldsPresent, nil -} - -// indirectBinder checks if dest implements Binder and returns reflect values. -func indirectBinder(dest interface{}) (interface{}, reflect.Value, reflect.Type) { - v := reflect.ValueOf(dest) - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Binder); ok { - return u, reflect.Value{}, nil - } - } - v = reflect.Indirect(v) - t := v.Type() - // Handle special types like time.Time and Date - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - return dest, reflect.Value{}, nil - } - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - return dest, reflect.Value{}, nil - } - return nil, v, t -} diff --git a/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl deleted file mode 100644 index a9bff4ab18..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_label.go.tmpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* BindLabelParam - label style without explode */}} - -// BindLabelParam binds a label-style parameter without explode to a destination. -// Label style values are prefixed with a dot. -// Primitives: .value -> "value" -// Arrays: .a,b,c -> []string{"a", "b", "c"} -// Objects: .key1,value1,key2,value2 -> struct{Key1, Key2} -func BindLabelParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Label style requires leading dot - if value[0] != '.' { - return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) - } - - // Strip the leading dot and split on comma - stripped := value[1:] - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(stripped)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - parts := strings.Split(stripped, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(stripped, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(stripped, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl deleted file mode 100644 index 766d29e3ea..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_label_explode.go.tmpl +++ /dev/null @@ -1,51 +0,0 @@ -{{/* BindLabelExplodeParam - label style with explode */}} - -// BindLabelExplodeParam binds a label-style parameter with explode to a destination. -// Label style values are prefixed with a dot. -// Primitives: .value -> "value" -// Arrays: .a.b.c -> []string{"a", "b", "c"} -// Objects: .key1=value1.key2=value2 -> struct{Key1, Key2} -func BindLabelExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Label style requires leading dot - if value[0] != '.' { - return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value[1:])) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on dot (skip first empty part) - parts := strings.Split(value, ".") - if parts[0] != "" { - return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) - } - return bindSplitPartsToDestinationStruct(paramName, parts[1:], true, dest) - case reflect.Slice: - // Split on dot (skip first empty part) - parts := strings.Split(value, ".") - if parts[0] != "" { - return fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName) - } - return bindSplitPartsToDestinationArray(parts[1:], dest) - default: - return BindStringToObject(value[1:], dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl deleted file mode 100644 index 0702dfa755..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_matrix.go.tmpl +++ /dev/null @@ -1,47 +0,0 @@ -{{/* BindMatrixParam - matrix style without explode */}} - -// BindMatrixParam binds a matrix-style parameter without explode to a destination. -// Matrix style values are prefixed with ;paramName=. -// Primitives: ;paramName=value -> "value" -// Arrays: ;paramName=a,b,c -> []string{"a", "b", "c"} -// Objects: ;paramName=key1,value1,key2,value2 -> struct{Key1, Key2} -func BindMatrixParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Matrix style requires ;paramName= prefix - prefix := ";" + paramName + "=" - if !strings.HasPrefix(value, prefix) { - return fmt.Errorf("expected parameter '%s' to start with %s", paramName, prefix) - } - - // Strip the prefix - stripped := strings.TrimPrefix(value, prefix) - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(stripped)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - parts := strings.Split(stripped, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(stripped, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(stripped, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl deleted file mode 100644 index 0b2f7ffd9a..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_matrix_explode.go.tmpl +++ /dev/null @@ -1,65 +0,0 @@ -{{/* BindMatrixExplodeParam - matrix style with explode */}} - -// BindMatrixExplodeParam binds a matrix-style parameter with explode to a destination. -// Matrix style values are prefixed with semicolons. -// Primitives: ;paramName=value -> "value" -// Arrays: ;paramName=a;paramName=b;paramName=c -> []string{"a", "b", "c"} -// Objects: ;key1=value1;key2=value2 -> struct{Key1, Key2} -func BindMatrixExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Break up on semicolon - parts := strings.Split(value, ";") - // First part should be empty since we start with ; - if parts[0] != "" { - return fmt.Errorf("invalid format for matrix parameter '%s', should start with ';'", paramName) - } - parts = parts[1:] - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - // For primitives, should be ;paramName=value - if len(parts) == 1 { - kv := strings.SplitN(parts[0], "=", 2) - if len(kv) == 2 && kv[0] == paramName { - return tu.UnmarshalText([]byte(kv[1])) - } - } - return fmt.Errorf("invalid format for matrix parameter '%s'", paramName) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // For objects, we have key1=value1, key2=value2 - return bindSplitPartsToDestinationStruct(paramName, parts, true, dest) - case reflect.Slice: - // For arrays, strip paramName= prefix from each part - prefix := paramName + "=" - values := make([]string, len(parts)) - for i, part := range parts { - values[i] = strings.TrimPrefix(part, prefix) - } - return bindSplitPartsToDestinationArray(values, dest) - default: - // Primitive: ;paramName=value - if len(parts) == 1 { - kv := strings.SplitN(parts[0], "=", 2) - if len(kv) == 2 && kv[0] == paramName { - return BindStringToObject(kv[1], dest) - } - } - return fmt.Errorf("invalid format for matrix parameter '%s'", paramName) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl deleted file mode 100644 index 1adfd9ef3e..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited.go.tmpl +++ /dev/null @@ -1,33 +0,0 @@ -{{/* BindPipeDelimitedParam - pipeDelimited style without explode */}} - -// BindPipeDelimitedParam binds a pipeDelimited-style parameter without explode. -// Pipe-delimited style uses pipe as the separator. -// Arrays: a|b|c -> []string{"a", "b", "c"} -func BindPipeDelimitedParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Slice: - parts := strings.Split(value, "|") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl deleted file mode 100644 index 9af6d4a5f3..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_pipe_delimited_explode.go.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{{/* BindPipeDelimitedExplodeParam - pipeDelimited style with explode */}} - -// BindPipeDelimitedExplodeParam binds a pipeDelimited-style parameter with explode. -// When exploded, arrays come as multiple query params (same as form explode). -// Arrays: ?param=a¶m=b -> []string{"a", "b"} -func BindPipeDelimitedExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - // Exploded pipe-delimited is same as exploded form - return BindFormExplodeParam(paramName, required, queryParams, dest) -} diff --git a/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl deleted file mode 100644 index 3b48a81c15..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_simple.go.tmpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* BindSimpleParam - simple style without explode */}} - -// BindSimpleParam binds a simple-style parameter without explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} -// Objects: key1,value1,key2,value2 -> struct{Key1, Key2} -func BindSimpleParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key,value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, false, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl deleted file mode 100644 index 3d9468f26a..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_simple_explode.go.tmpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* BindSimpleExplodeParam - simple style with explode */}} - -// BindSimpleExplodeParam binds a simple-style parameter with explode to a destination. -// Simple style is the default for path and header parameters. -// Arrays: a,b,c -> []string{"a", "b", "c"} (same as non-explode) -// Objects: key1=value1,key2=value2 -> struct{Key1, Key2} -func BindSimpleExplodeParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Struct: - // Split on comma and bind as key=value pairs - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationStruct(paramName, parts, true, dest) - case reflect.Slice: - parts := strings.Split(value, ",") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl deleted file mode 100644 index b7b83685df..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_space_delimited.go.tmpl +++ /dev/null @@ -1,33 +0,0 @@ -{{/* BindSpaceDelimitedParam - spaceDelimited style without explode */}} - -// BindSpaceDelimitedParam binds a spaceDelimited-style parameter without explode. -// Space-delimited style uses space as the separator. -// Arrays: a b c -> []string{"a", "b", "c"} -func BindSpaceDelimitedParam(paramName string, paramLocation ParamLocation, value string, dest interface{}) error { - if value == "" { - return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName) - } - - // Unescape based on location - var err error - value, err = unescapeParameterString(value, paramLocation) - if err != nil { - return fmt.Errorf("error unescaping parameter '%s': %w", paramName, err) - } - - // Check for TextUnmarshaler - if tu, ok := dest.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(value)) - } - - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - switch t.Kind() { - case reflect.Slice: - parts := strings.Split(value, " ") - return bindSplitPartsToDestinationArray(parts, dest) - default: - return BindStringToObject(value, dest) - } -} diff --git a/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl deleted file mode 100644 index f79f097eff..0000000000 --- a/experimental/internal/codegen/templates/files/params/bind_space_delimited_explode.go.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{{/* BindSpaceDelimitedExplodeParam - spaceDelimited style with explode */}} - -// BindSpaceDelimitedExplodeParam binds a spaceDelimited-style parameter with explode. -// When exploded, arrays come as multiple query params (same as form explode). -// Arrays: ?param=a¶m=b -> []string{"a", "b"} -func BindSpaceDelimitedExplodeParam(paramName string, required bool, queryParams url.Values, dest interface{}) error { - // Exploded space-delimited is same as exploded form - return BindFormExplodeParam(paramName, required, queryParams, dest) -} diff --git a/experimental/internal/codegen/templates/files/params/helpers.go.tmpl b/experimental/internal/codegen/templates/files/params/helpers.go.tmpl deleted file mode 100644 index b3f650f211..0000000000 --- a/experimental/internal/codegen/templates/files/params/helpers.go.tmpl +++ /dev/null @@ -1,260 +0,0 @@ -{{/* Parameter styling and binding helper functions - included when any param function is used */}} - -// ParamLocation indicates where a parameter is located in an HTTP request. -type ParamLocation int - -const ( - ParamLocationUndefined ParamLocation = iota - ParamLocationQuery - ParamLocationPath - ParamLocationHeader - ParamLocationCookie -) - -// Binder is an interface for types that can bind themselves from a string value. -type Binder interface { - Bind(value string) error -} - -// DateFormat is the format used for date (without time) parameters. -const DateFormat = "2006-01-02" - -// Date represents a date (without time) for OpenAPI date format. -type Date struct { - time.Time -} - -// UnmarshalText implements encoding.TextUnmarshaler for Date. -func (d *Date) UnmarshalText(data []byte) error { - t, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = t - return nil -} - -// MarshalText implements encoding.TextMarshaler for Date. -func (d Date) MarshalText() ([]byte, error) { - return []byte(d.Format(DateFormat)), nil -} - -// Format returns the date formatted according to layout. -func (d Date) Format(layout string) string { - return d.Time.Format(layout) -} - -// primitiveToString converts a primitive value to a string representation. -// It handles basic Go types, time.Time, types.Date, and types that implement -// json.Marshaler or fmt.Stringer. -func primitiveToString(value interface{}) (string, error) { - // Check for known types first (time, date, uuid) - if res, ok := marshalKnownTypes(value); ok { - return res, nil - } - - // Dereference pointers for optional values - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - kind := t.Kind() - - switch kind { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return strconv.FormatInt(v.Int(), 10), nil - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return strconv.FormatUint(v.Uint(), 10), nil - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil - case reflect.Bool: - if v.Bool() { - return "true", nil - } - return "false", nil - case reflect.String: - return v.String(), nil - case reflect.Struct: - // Check if it's a UUID - if u, ok := value.(uuid.UUID); ok { - return u.String(), nil - } - // Check if it implements json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - var i2 interface{} - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to decode JSON: %w", err) - } - return primitiveToString(i2) - } - fallthrough - default: - if s, ok := value.(fmt.Stringer); ok { - return s.String(), nil - } - return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String()) - } -} - -// marshalKnownTypes checks for special types (time.Time, Date, UUID) and marshals them. -func marshalKnownTypes(value interface{}) (string, bool) { - v := reflect.Indirect(reflect.ValueOf(value)) - t := v.Type() - - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { - tt := v.Convert(reflect.TypeOf(time.Time{})) - timeVal := tt.Interface().(time.Time) - return timeVal.Format(time.RFC3339Nano), true - } - - if t.ConvertibleTo(reflect.TypeOf(Date{})) { - d := v.Convert(reflect.TypeOf(Date{})) - dateVal := d.Interface().(Date) - return dateVal.Format(DateFormat), true - } - - if t.ConvertibleTo(reflect.TypeOf(uuid.UUID{})) { - u := v.Convert(reflect.TypeOf(uuid.UUID{})) - uuidVal := u.Interface().(uuid.UUID) - return uuidVal.String(), true - } - - return "", false -} - -// escapeParameterString escapes a parameter value based on its location. -// Query and path parameters need URL escaping; headers and cookies do not. -func escapeParameterString(value string, paramLocation ParamLocation) string { - switch paramLocation { - case ParamLocationQuery: - return url.QueryEscape(value) - case ParamLocationPath: - return url.PathEscape(value) - default: - return value - } -} - -// unescapeParameterString unescapes a parameter value based on its location. -func unescapeParameterString(value string, paramLocation ParamLocation) (string, error) { - switch paramLocation { - case ParamLocationQuery, ParamLocationUndefined: - return url.QueryUnescape(value) - case ParamLocationPath: - return url.PathUnescape(value) - default: - return value, nil - } -} - -// sortedKeys returns the keys of a map in sorted order. -func sortedKeys(m map[string]string) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - -// BindStringToObject binds a string value to a destination object. -// It handles primitives, encoding.TextUnmarshaler, and the Binder interface. -func BindStringToObject(src string, dst interface{}) error { - // Check for TextUnmarshaler - if tu, ok := dst.(encoding.TextUnmarshaler); ok { - return tu.UnmarshalText([]byte(src)) - } - - // Check for Binder interface - if b, ok := dst.(Binder); ok { - return b.Bind(src) - } - - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr { - return fmt.Errorf("dst must be a pointer, got %T", dst) - } - v = v.Elem() - - switch v.Kind() { - case reflect.String: - v.SetString(src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i, err := strconv.ParseInt(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse int: %w", err) - } - v.SetInt(i) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u, err := strconv.ParseUint(src, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse uint: %w", err) - } - v.SetUint(u) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(src, 64) - if err != nil { - return fmt.Errorf("failed to parse float: %w", err) - } - v.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(src) - if err != nil { - return fmt.Errorf("failed to parse bool: %w", err) - } - v.SetBool(b) - default: - // Try JSON unmarshal as a fallback - return json.Unmarshal([]byte(src), dst) - } - return nil -} - -// bindSplitPartsToDestinationArray binds a slice of string parts to a destination slice. -func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error { - v := reflect.Indirect(reflect.ValueOf(dest)) - t := v.Type() - - newArray := reflect.MakeSlice(t, len(parts), len(parts)) - for i, p := range parts { - err := BindStringToObject(p, newArray.Index(i).Addr().Interface()) - if err != nil { - return fmt.Errorf("error setting array element: %w", err) - } - } - v.Set(newArray) - return nil -} - -// bindSplitPartsToDestinationStruct binds string parts to a destination struct via JSON. -func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error { - var fields []string - if explode { - fields = make([]string, len(parts)) - for i, property := range parts { - propertyParts := strings.Split(property, "=") - if len(propertyParts) != 2 { - return fmt.Errorf("parameter '%s' has invalid exploded format", paramName) - } - fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\"" - } - } else { - if len(parts)%2 != 0 { - return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName) - } - fields = make([]string, len(parts)/2) - for i := 0; i < len(parts); i += 2 { - key := parts[i] - value := parts[i+1] - fields[i/2] = "\"" + key + "\":\"" + value + "\"" - } - } - jsonParam := "{" + strings.Join(fields, ",") + "}" - return json.Unmarshal([]byte(jsonParam), dest) -} diff --git a/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl b/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl deleted file mode 100644 index 753ff4433a..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_deep_object.go.tmpl +++ /dev/null @@ -1,74 +0,0 @@ -{{/* StyleDeepObjectParam - deepObject style (always exploded) */}} - -// StyleDeepObjectParam serializes a value using deepObject style. -// DeepObject style is only valid for query parameters with object values and must be exploded. -// Objects: paramName[key1]=value1¶mName[key2]=value2 -// Nested: paramName[outer][inner]=value -func StyleDeepObjectParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // deepObject always requires explode=true - return MarshalDeepObject(value, paramName) -} - -// MarshalDeepObject marshals an object to deepObject style query parameters. -func MarshalDeepObject(i interface{}, paramName string) (string, error) { - // Marshal to JSON first to handle all field annotations - buf, err := json.Marshal(i) - if err != nil { - return "", fmt.Errorf("failed to marshal input to JSON: %w", err) - } - var i2 interface{} - err = json.Unmarshal(buf, &i2) - if err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - fields, err := marshalDeepObjectRecursive(i2, nil) - if err != nil { - return "", fmt.Errorf("error traversing JSON structure: %w", err) - } - - // Prefix the param name to each subscripted field - for idx := range fields { - fields[idx] = paramName + fields[idx] - } - return strings.Join(fields, "&"), nil -} - -func marshalDeepObjectRecursive(in interface{}, path []string) ([]string, error) { - var result []string - - switch t := in.(type) { - case []interface{}: - // Arrays use numerical subscripts [0], [1], etc. - for i, iface := range t { - newPath := append(path, strconv.Itoa(i)) - fields, err := marshalDeepObjectRecursive(iface, newPath) - if err != nil { - return nil, fmt.Errorf("error traversing array: %w", err) - } - result = append(result, fields...) - } - case map[string]interface{}: - // Maps use key subscripts [key1], [key2], etc. - keys := make([]string, 0, len(t)) - for k := range t { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - newPath := append(path, k) - fields, err := marshalDeepObjectRecursive(t[k], newPath) - if err != nil { - return nil, fmt.Errorf("error traversing map: %w", err) - } - result = append(result, fields...) - } - default: - // Concrete value: turn path into [a][b][c] format - prefix := "[" + strings.Join(path, "][") + "]" - result = []string{ - prefix + fmt.Sprintf("=%v", t), - } - } - return result, nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_form.go.tmpl b/experimental/internal/codegen/templates/files/params/style_form.go.tmpl deleted file mode 100644 index 91df97e6e0..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_form.go.tmpl +++ /dev/null @@ -1,132 +0,0 @@ -{{/* StyleFormParam - form style without explode */}} - -// StyleFormParam serializes a value using form style (RFC 6570) without exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a,b,c -// Objects: paramName=key1,value1,key2,value2 -func StyleFormParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormMap(paramName, paramLocation, value) - default: - return styleFormPrimitive(paramName, paramLocation, value) - } -} - -func styleFormPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form without explode: paramName=a,b,c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, ","), nil -} - -func styleFormStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style without explode: paramName=key1,value1,key2,value2 - prefix := fmt.Sprintf("%s=", paramName) - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return prefix + strings.Join(parts, ","), nil -} - -func styleFormMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style without explode: paramName=key1,value1,key2,value2 - prefix := fmt.Sprintf("%s=", paramName) - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return prefix + strings.Join(parts, ","), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl deleted file mode 100644 index a39c67c21b..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_form_explode.go.tmpl +++ /dev/null @@ -1,130 +0,0 @@ -{{/* StyleFormExplodeParam - form style with explode */}} - -// StyleFormExplodeParam serializes a value using form style (RFC 6570) with exploding. -// Form style is the default for query and cookie parameters. -// Primitives: paramName=value -// Arrays: paramName=a¶mName=b¶mName=c -// Objects: key1=value1&key2=value2 -func StyleFormExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleFormExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleFormExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleFormExplodeMap(paramName, paramLocation, value) - default: - return styleFormExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleFormExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleFormExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Form with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} - -func styleFormExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleFormExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} - -func styleFormExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Form style with explode: key1=value1&key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, "&"), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_label.go.tmpl b/experimental/internal/codegen/templates/files/params/style_label.go.tmpl deleted file mode 100644 index def8c74ee0..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_label.go.tmpl +++ /dev/null @@ -1,129 +0,0 @@ -{{/* StyleLabelParam - label style without explode */}} - -// StyleLabelParam serializes a value using label style (RFC 6570) without exploding. -// Label style prefixes values with a dot. -// Primitives: .value -// Arrays: .a,b,c -// Objects: .key1,value1,key2,value2 -func StyleLabelParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return "." + escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleLabelSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleLabelStruct(paramName, paramLocation, value) - case reflect.Map: - return styleLabelMap(paramName, paramLocation, value) - default: - return styleLabelPrimitive(paramLocation, value) - } -} - -func styleLabelPrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return "." + escapeParameterString(strVal, paramLocation), nil -} - -func styleLabelSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Label without explode: .a,b,c - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return "." + strings.Join(parts, ","), nil -} - -func styleLabelStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return "." + escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleLabelParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Label style without explode: .key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return "." + strings.Join(parts, ","), nil -} - -func styleLabelMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Label style without explode: .key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return "." + strings.Join(parts, ","), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl deleted file mode 100644 index c770480811..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_label_explode.go.tmpl +++ /dev/null @@ -1,129 +0,0 @@ -{{/* StyleLabelExplodeParam - label style with explode */}} - -// StyleLabelExplodeParam serializes a value using label style (RFC 6570) with exploding. -// Label style prefixes values with a dot. -// Primitives: .value -// Arrays: .a.b.c -// Objects: .key1=value1.key2=value2 -func StyleLabelExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return "." + escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleLabelExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleLabelExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleLabelExplodeMap(paramName, paramLocation, value) - default: - return styleLabelExplodePrimitive(paramLocation, value) - } -} - -func styleLabelExplodePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return "." + escapeParameterString(strVal, paramLocation), nil -} - -func styleLabelExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Label with explode: .a.b.c - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return "." + strings.Join(parts, "."), nil -} - -func styleLabelExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return "." + escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleLabelExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Label style with explode: .key1=value1.key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return "." + strings.Join(parts, "."), nil -} - -func styleLabelExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Label style with explode: .key1=value1.key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return "." + strings.Join(parts, "."), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl b/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl deleted file mode 100644 index 49c001f9dc..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_matrix.go.tmpl +++ /dev/null @@ -1,132 +0,0 @@ -{{/* StyleMatrixParam - matrix style without explode */}} - -// StyleMatrixParam serializes a value using matrix style (RFC 6570) without exploding. -// Matrix style prefixes values with ;paramName=. -// Primitives: ;paramName=value -// Arrays: ;paramName=a,b,c -// Objects: ;paramName=key1,value1,key2,value2 -func StyleMatrixParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleMatrixSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleMatrixStruct(paramName, paramLocation, value) - case reflect.Map: - return styleMatrixMap(paramName, paramLocation, value) - default: - return styleMatrixPrimitive(paramName, paramLocation, value) - } -} - -func styleMatrixPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleMatrixSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Matrix without explode: ;paramName=a,b,c - prefix := fmt.Sprintf(";%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, ","), nil -} - -func styleMatrixStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleMatrixParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Matrix style without explode: ;paramName=key1,value1,key2,value2 - prefix := fmt.Sprintf(";%s=", paramName) - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return prefix + strings.Join(parts, ","), nil -} - -func styleMatrixMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Matrix style without explode: ;paramName=key1,value1,key2,value2 - prefix := fmt.Sprintf(";%s=", paramName) - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return prefix + strings.Join(parts, ","), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl deleted file mode 100644 index 63790426f4..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_matrix_explode.go.tmpl +++ /dev/null @@ -1,130 +0,0 @@ -{{/* StyleMatrixExplodeParam - matrix style with explode */}} - -// StyleMatrixExplodeParam serializes a value using matrix style (RFC 6570) with exploding. -// Matrix style prefixes values with ;paramName=. -// Primitives: ;paramName=value -// Arrays: ;paramName=a;paramName=b;paramName=c -// Objects: ;key1=value1;key2=value2 -func StyleMatrixExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleMatrixExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleMatrixExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleMatrixExplodeMap(paramName, paramLocation, value) - default: - return styleMatrixExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleMatrixExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleMatrixExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Matrix with explode: ;paramName=a;paramName=b;paramName=c - prefix := fmt.Sprintf(";%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, prefix), nil -} - -func styleMatrixExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return fmt.Sprintf(";%s=%s", paramName, escapeParameterString(timeVal, paramLocation)), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleMatrixExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Matrix style with explode: ;key1=value1;key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return ";" + strings.Join(parts, ";"), nil -} - -func styleMatrixExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Matrix style with explode: ;key1=value1;key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return ";" + strings.Join(parts, ";"), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl deleted file mode 100644 index de7022ecda..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_pipe_delimited.go.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -{{/* StylePipeDelimitedParam - pipeDelimited style without explode */}} - -// StylePipeDelimitedParam serializes a value using pipeDelimited style without exploding. -// Pipe-delimited style is used for query parameters with array values. -// Arrays: paramName=a|b|c -// Note: Only valid for arrays; objects should use other styles. -func StylePipeDelimitedParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return stylePipeDelimitedSlice(paramName, paramLocation, sliceVal) - default: - // For primitives, fall back to form style - return stylePipeDelimitedPrimitive(paramName, paramLocation, value) - } -} - -func stylePipeDelimitedPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func stylePipeDelimitedSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Pipe-delimited without explode: paramName=a|b|c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "|"), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl deleted file mode 100644 index fa156dea7e..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_pipe_delimited_explode.go.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -{{/* StylePipeDelimitedExplodeParam - pipeDelimited style with explode */}} - -// StylePipeDelimitedExplodeParam serializes a value using pipeDelimited style with exploding. -// Pipe-delimited style is used for query parameters with array values. -// Arrays: paramName=a¶mName=b¶mName=c (same as form explode) -// Note: Only valid for arrays; objects should use other styles. -func StylePipeDelimitedExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return stylePipeDelimitedExplodeSlice(paramName, paramLocation, sliceVal) - default: - // For primitives, fall back to form style - return stylePipeDelimitedExplodePrimitive(paramName, paramLocation, value) - } -} - -func stylePipeDelimitedExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func stylePipeDelimitedExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Pipe-delimited with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl b/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl deleted file mode 100644 index 7476b2d4a4..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_simple.go.tmpl +++ /dev/null @@ -1,158 +0,0 @@ -{{/* StyleSimpleParam - simple style without explode */}} - -// StyleSimpleParam serializes a value using simple style (RFC 6570) without exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c -// Objects are key,value pairs: key1,value1,key2,value2 -func StyleSimpleParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleMap(paramName, paramLocation, value) - default: - return styleSimplePrimitive(paramLocation, value) - } -} - -func styleSimplePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style without explode: key1,value1,key2,value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k, v) - } - return strings.Join(parts, ","), nil -} - -// structToFieldDict converts a struct to a map of field names to string values. -func structToFieldDict(value interface{}) (map[string]string, error) { - v := reflect.ValueOf(value) - t := reflect.TypeOf(value) - fieldDict := make(map[string]string) - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i) - tag := fieldT.Tag.Get("json") - fieldName := fieldT.Name - if tag != "" { - tagParts := strings.Split(tag, ",") - if tagParts[0] != "" { - fieldName = tagParts[0] - } - } - f := v.Field(i) - - // Skip nil optional fields - if f.Type().Kind() == reflect.Ptr && f.IsNil() { - continue - } - str, err := primitiveToString(f.Interface()) - if err != nil { - return nil, fmt.Errorf("error formatting field '%s': %w", fieldName, err) - } - fieldDict[fieldName] = str - } - return fieldDict, nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl deleted file mode 100644 index 38dc6d3983..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_simple_explode.go.tmpl +++ /dev/null @@ -1,128 +0,0 @@ -{{/* StyleSimpleExplodeParam - simple style with explode */}} - -// StyleSimpleExplodeParam serializes a value using simple style (RFC 6570) with exploding. -// Simple style is the default for path and header parameters. -// Arrays are comma-separated: a,b,c (same as non-explode) -// Objects are key=value pairs: key1=value1,key2=value2 -func StyleSimpleExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return escapeParameterString(string(b), paramLocation), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSimpleExplodeSlice(paramName, paramLocation, sliceVal) - case reflect.Struct: - return styleSimpleExplodeStruct(paramName, paramLocation, value) - case reflect.Map: - return styleSimpleExplodeMap(paramName, paramLocation, value) - default: - return styleSimpleExplodePrimitive(paramLocation, value) - } -} - -func styleSimpleExplodePrimitive(paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return escapeParameterString(strVal, paramLocation), nil -} - -func styleSimpleExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Exploded simple array is same as non-exploded: comma-separated - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleExplodeStruct(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - // Check for known types first - if timeVal, ok := marshalKnownTypes(value); ok { - return escapeParameterString(timeVal, paramLocation), nil - } - - // Check for json.Marshaler - if m, ok := value.(json.Marshaler); ok { - buf, err := m.MarshalJSON() - if err != nil { - return "", fmt.Errorf("failed to marshal to JSON: %w", err) - } - var i2 interface{} - e := json.NewDecoder(bytes.NewReader(buf)) - e.UseNumber() - if err = e.Decode(&i2); err != nil { - return "", fmt.Errorf("failed to unmarshal JSON: %w", err) - } - return StyleSimpleExplodeParam(paramName, paramLocation, i2) - } - - // Build field dictionary - fieldDict, err := structToFieldDict(value) - if err != nil { - return "", err - } - - // Simple style with explode: key1=value1,key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, ","), nil -} - -func styleSimpleExplodeMap(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - dict, ok := value.(map[string]interface{}) - if !ok { - return "", errors.New("map not of type map[string]interface{}") - } - - fieldDict := make(map[string]string) - for fieldName, val := range dict { - str, err := primitiveToString(val) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - fieldDict[fieldName] = str - } - - // Simple style with explode: key1=value1,key2=value2 - var parts []string - for _, k := range sortedKeys(fieldDict) { - v := escapeParameterString(fieldDict[k], paramLocation) - parts = append(parts, k+"="+v) - } - return strings.Join(parts, ","), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl b/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl deleted file mode 100644 index 7256e3a43c..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_space_delimited.go.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -{{/* StyleSpaceDelimitedParam - spaceDelimited style without explode */}} - -// StyleSpaceDelimitedParam serializes a value using spaceDelimited style without exploding. -// Space-delimited style is used for query parameters with array values. -// Arrays: paramName=a b c (space-separated) -// Note: Only valid for arrays; objects should use other styles. -func StyleSpaceDelimitedParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSpaceDelimitedSlice(paramName, paramLocation, sliceVal) - default: - // For primitives, fall back to form style - return styleSpaceDelimitedPrimitive(paramName, paramLocation, value) - } -} - -func styleSpaceDelimitedPrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleSpaceDelimitedSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Space-delimited without explode: paramName=a b c (space becomes %20 when encoded) - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, " "), nil -} diff --git a/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl b/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl deleted file mode 100644 index e32813ba91..0000000000 --- a/experimental/internal/codegen/templates/files/params/style_space_delimited_explode.go.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -{{/* StyleSpaceDelimitedExplodeParam - spaceDelimited style with explode */}} - -// StyleSpaceDelimitedExplodeParam serializes a value using spaceDelimited style with exploding. -// Space-delimited style is used for query parameters with array values. -// Arrays: paramName=a¶mName=b¶mName=c (same as form explode) -// Note: Only valid for arrays; objects should use other styles. -func StyleSpaceDelimitedExplodeParam(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - t := reflect.TypeOf(value) - v := reflect.ValueOf(value) - - // Dereference pointers - if t.Kind() == reflect.Ptr { - if v.IsNil() { - return "", fmt.Errorf("value is a nil pointer") - } - v = reflect.Indirect(v) - t = v.Type() - } - - // Check for TextMarshaler (but not time.Time or Date) - if tu, ok := value.(encoding.TextMarshaler); ok { - innerT := reflect.Indirect(reflect.ValueOf(value)).Type() - if !innerT.ConvertibleTo(reflect.TypeOf(time.Time{})) && !innerT.ConvertibleTo(reflect.TypeOf(Date{})) { - b, err := tu.MarshalText() - if err != nil { - return "", fmt.Errorf("error marshaling '%s' as text: %w", value, err) - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(string(b), paramLocation)), nil - } - } - - switch t.Kind() { - case reflect.Slice: - n := v.Len() - sliceVal := make([]interface{}, n) - for i := 0; i < n; i++ { - sliceVal[i] = v.Index(i).Interface() - } - return styleSpaceDelimitedExplodeSlice(paramName, paramLocation, sliceVal) - default: - // For primitives, fall back to form style - return styleSpaceDelimitedExplodePrimitive(paramName, paramLocation, value) - } -} - -func styleSpaceDelimitedExplodePrimitive(paramName string, paramLocation ParamLocation, value interface{}) (string, error) { - strVal, err := primitiveToString(value) - if err != nil { - return "", err - } - return fmt.Sprintf("%s=%s", paramName, escapeParameterString(strVal, paramLocation)), nil -} - -func styleSpaceDelimitedExplodeSlice(paramName string, paramLocation ParamLocation, values []interface{}) (string, error) { - // Space-delimited with explode: paramName=a¶mName=b¶mName=c - prefix := fmt.Sprintf("%s=", paramName) - parts := make([]string, len(values)) - for i, v := range values { - part, err := primitiveToString(v) - if err != nil { - return "", fmt.Errorf("error formatting '%s': %w", paramName, err) - } - parts[i] = escapeParameterString(part, paramLocation) - } - return prefix + strings.Join(parts, "&"+prefix), nil -} diff --git a/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl deleted file mode 100644 index ccd9653b40..0000000000 --- a/experimental/internal/codegen/templates/files/server/chi/handler.go.tmpl +++ /dev/null @@ -1,59 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Chi servers. - Input: []OperationDescriptor -*/ -}} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{}) -} - -// ChiServerOptions configures the Chi server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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) - } - } -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, - } -{{ end }} -{{- range . }} - r.Group(func(r chi.Router) { - r.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToChiPattern .Path }}", wrapper.{{ .GoOperationID }}) - }) -{{- end }} - return r -} diff --git a/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl deleted file mode 100644 index 010ed1b157..0000000000 --- a/experimental/internal/codegen/templates/files/server/chi/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Chi servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { - w.WriteHeader(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl deleted file mode 100644 index dce41f1d14..0000000000 --- a/experimental/internal/codegen/templates/files/server/chi/receiver.go.tmpl +++ /dev/null @@ -1,95 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Chi. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. -type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) - return - }{{ end }} -{{ end }} -{{- end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl deleted file mode 100644 index 91d346b682..0000000000 --- a/experimental/internal/codegen/templates/files/server/chi/wrapper.go.tmpl +++ /dev/null @@ -1,166 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Chi. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -{{ range . }} -// {{ .GoOperationID }} operation middleware -func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = chi.URLParam(r, "{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(chi.URLParam(r, "{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, chi.URLParam(r, "{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{- if .Security }} - ctx := r.Context() -{{- range .Security }} - ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} - r = r.WithContext(ctx) -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := r.Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") - siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) - return - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - { - var cookie *http.Cookie - if cookie, err = r.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} - } -{{ end }} -{{ end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl deleted file mode 100644 index fcbb54b60d..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo-v4/handler.go.tmpl +++ /dev/null @@ -1,34 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Echo servers. - Input: []OperationDescriptor -*/ -}} - -// EchoRouter is an interface for echo.Echo and echo.Group. -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, "") -} - -// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - } -{{ end }} -{{- range . }} - router.{{ .Method }}(baseURL+"{{ pathToEchoPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl deleted file mode 100644 index 22cb0ebe68..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo-v4/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Echo servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(ctx echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(ctx echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { - return ctx.NoContent(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl deleted file mode 100644 index 0fa1b97708..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo-v4/receiver.go.tmpl +++ /dev/null @@ -1,72 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Echo v4. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx echo.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an echo.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) echo.HandlerFunc { - return func(ctx echo.Context) error { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query parameter {{ .Name }} is required")) - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required")) - }{{ end }} -{{ end }} -{{- end }} - return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) - } -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl deleted file mode 100644 index 6847388a7e..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo-v4/wrapper.go.tmpl +++ /dev/null @@ -1,134 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Echo. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -{{ range . }} -// {{ .GoOperationID }} converts echo context to params. -func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx echo.Context) error { - var err error - -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = ctx.Param("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(ctx.Param("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Param("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{- if .Security }} -{{- range .Security }} - ctx.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- else }} - if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) - }{{ end }} -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := ctx.Request().Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required, but not found")) - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - if cookie, err := ctx.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) - }{{ end }} -{{ end }} -{{ end }} - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) - return err -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl deleted file mode 100644 index 0e6d2dbd01..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo/handler.go.tmpl +++ /dev/null @@ -1,35 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Echo v5 servers. - Input: []OperationDescriptor -*/ -}} - -// EchoRouter is an interface for echo.Echo and echo.Group. -type EchoRouter interface { - Add(method string, path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo - 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 -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router EchoRouter, si ServerInterface) { - RegisterHandlersWithBaseURL(router, si, "") -} - -// RegisterHandlersWithBaseURL adds each server route to the EchoRouter with a base URL prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - } -{{ end }} -{{- range . }} - router.{{ .Method }}(baseURL+"{{ pathToEchoPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl deleted file mode 100644 index e1c4ac779a..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Echo v5 servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(ctx *echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(ctx *echo.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { - return ctx.NoContent(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl deleted file mode 100644 index 8a336c5e23..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo/receiver.go.tmpl +++ /dev/null @@ -1,72 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Echo v5. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx *echo.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an echo.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) echo.HandlerFunc { - return func(ctx *echo.Context) error { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query parameter {{ .Name }} is required")) - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required")) - }{{ end }} -{{ end }} -{{- end }} - return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) - } -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl deleted file mode 100644 index ae92e02879..0000000000 --- a/experimental/internal/codegen/templates/files/server/echo/wrapper.go.tmpl +++ /dev/null @@ -1,134 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Echo v5. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -{{ range . }} -// {{ .GoOperationID }} converts echo context to params. -func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx *echo.Context) error { - var err error - -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = ctx.Param("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(ctx.Param("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Param("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{- if .Security }} -{{- range .Security }} - ctx.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), ¶ms.{{ .GoName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- else }} - if paramValue := ctx.QueryParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) - }{{ end }} -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := ctx.Request().Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{ .Name }} is required, but not found")) - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - if cookie, err := ctx.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{ .Name }} is required, but not found")) - }{{ end }} -{{ end }} -{{ end }} - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) - return err -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/errors.go.tmpl b/experimental/internal/codegen/templates/files/server/errors.go.tmpl deleted file mode 100644 index c4727ef976..0000000000 --- a/experimental/internal/codegen/templates/files/server/errors.go.tmpl +++ /dev/null @@ -1,79 +0,0 @@ -{{- /* - This template generates error types for server parameter handling. - These are shared across all router implementations. -*/ -}} - -// UnescapedCookieParamError is returned when a cookie parameter cannot be unescaped. -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 -} - -// UnmarshalingParamError is returned when a parameter cannot be unmarshaled. -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 -} - -// RequiredParamError is returned when a required parameter is missing. -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -// RequiredHeaderError is returned when a required header is missing. -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 -} - -// InvalidParamFormatError is returned when a parameter has an invalid format. -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 -} - -// TooManyValuesForParamError is returned when a parameter has too many values. -type TooManyValuesForParamError struct { - ParamName string - Count int -} - -func (e *TooManyValuesForParamError) Error() string { - return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) -} diff --git a/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl deleted file mode 100644 index b6e59cfb75..0000000000 --- a/experimental/internal/codegen/templates/files/server/fiber/handler.go.tmpl +++ /dev/null @@ -1,31 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Fiber servers. - Input: []OperationDescriptor -*/ -}} - -// FiberServerOptions provides options for the Fiber server. -type FiberServerOptions struct { - BaseURL string - Middlewares []fiber.Handler -} - -// 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) { -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - for _, m := range options.Middlewares { - router.Use(m) - } -{{ end }} -{{- range . }} - router.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToFiberPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl deleted file mode 100644 index dddefc81c6..0000000000 --- a/experimental/internal/codegen/templates/files/server/fiber/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Fiber servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(c fiber.Ctx{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(c fiber.Ctx{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error { - return c.SendStatus(fiber.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl deleted file mode 100644 index 5775f45ed1..0000000000 --- a/experimental/internal/codegen/templates/files/server/fiber/receiver.go.tmpl +++ /dev/null @@ -1,71 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Fiber. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(c fiber.Ctx{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) error -{{- end }} -} - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns a fiber.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) fiber.Handler { - return func(c fiber.Ctx) error { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := c.Query("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return fiber.NewError(http.StatusBadRequest, "Query parameter {{ .Name }} is required") - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Queries(), ¶ms.{{ .GoName }}) - if err != nil { - return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - { - headerValue := c.Get("{{ .Name }}") - if headerValue != "" { - var {{ .GoVariableName }} {{ .TypeDecl }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, headerValue, &{{ .GoVariableName }}) - if err != nil { - return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return fiber.NewError(http.StatusBadRequest, "Header parameter {{ .Name }} is required") - }{{ end }} - } -{{ end }} -{{- end }} - return si.Handle{{ .GoOperationID }}{{ $.Prefix }}(c{{ if .HasParams }}, params{{ end }}) - } -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl deleted file mode 100644 index 7abbd2da7a..0000000000 --- a/experimental/internal/codegen/templates/files/server/fiber/wrapper.go.tmpl +++ /dev/null @@ -1,137 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Fiber. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -{{ range . }} -// {{ .GoOperationID }} operation middleware -func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c fiber.Ctx) error { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = c.Params("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(c.Params("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, c.Params("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} -{{ end }} -{{- if .Security }} -{{- range .Security }} - c.Locals({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ if .QueryParams }} - var query url.Values - query, err = url.ParseQuery(string(c.Request().URI().QueryString())) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for query string: %s", err)) - } -{{ end }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, query, ¶ms.{{ .GoName }}) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- else if or .Required .IsPassThrough .IsJSON }} - if paramValue := c.Query("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return fiber.NewError(fiber.StatusBadRequest, "Query argument {{ .Name }} is required, but not found") - }{{ end }} -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := c.GetReqHeaders() -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found && len(valueList) > 0 { - var {{ .GoVariableName }} {{ .TypeDecl }} - value := valueList[0] -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(value), &{{ .GoVariableName }}) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, value, &{{ .GoVariableName }}) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - return fiber.NewError(fiber.StatusBadRequest, "Header parameter {{ .Name }} is required, but not found") - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - if cookie := c.Cookies("{{ .Name }}"); cookie != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unescaping cookie parameter '%s': %s", "{{ .Name }}", err)) - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Error unmarshaling parameter '%s' as JSON: %s", "{{ .Name }}", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - return fiber.NewError(fiber.StatusBadRequest, "Query argument {{ .Name }} is required, but not found") - }{{ end }} -{{ end }} -{{ end }} - return siw.Handler.{{ .GoOperationID }}(c{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl deleted file mode 100644 index 3ba848a34a..0000000000 --- a/experimental/internal/codegen/templates/files/server/gin/handler.go.tmpl +++ /dev/null @@ -1,37 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Gin servers. - Input: []OperationDescriptor -*/ -}} - -// 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) { -{{ if . }} - 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, - } -{{ end }} -{{- range . }} - router.{{ .Method }}(options.BaseURL+"{{ pathToGinPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl deleted file mode 100644 index a2b22df6d6..0000000000 --- a/experimental/internal/codegen/templates/files/server/gin/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Gin servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(c *gin.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(c *gin.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { - c.Status(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl deleted file mode 100644 index 1b150abc7b..0000000000 --- a/experimental/internal/codegen/templates/files/server/gin/receiver.go.tmpl +++ /dev/null @@ -1,78 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Gin. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(c *gin.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns a gin.HandlerFunc for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) gin.HandlerFunc { - return func(c *gin.Context) { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := c.Query("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - c.JSON(http.StatusBadRequest, gin.H{"error": "Query parameter {{ .Name }} is required"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Request.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) - return - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList := c.Request.Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)}) - return - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - c.JSON(http.StatusBadRequest, gin.H{"error": "Header parameter {{ .Name }} is required"}) - return - }{{ end }} -{{ end }} -{{- end }} - si.Handle{{ .GoOperationID }}{{ $.Prefix }}(c{{ if .HasParams }}, params{{ end }}) - } -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl deleted file mode 100644 index 1fb5792ee5..0000000000 --- a/experimental/internal/codegen/templates/files/server/gin/wrapper.go.tmpl +++ /dev/null @@ -1,161 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Gin. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandler func(*gin.Context, error, int) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(c *gin.Context) - -{{ range . }} -// {{ .GoOperationID }} operation middleware -func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c *gin.Context) { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = c.Param("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(c.Param("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, c.Param("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) - return - } -{{- end }} -{{ end }} -{{- if .Security }} -{{- range .Security }} - c.Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Request.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) - return - } -{{- else if or .Required .IsPassThrough .IsJSON }} - if paramValue := c.Query("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON: %w", err), http.StatusBadRequest) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandler(c, fmt.Errorf("Query argument {{ .Name }} is required, but not found"), http.StatusBadRequest) - return - }{{ end }} -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := c.Request.Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - siw.ErrorHandler(c, fmt.Errorf("Expected one value for {{ .Name }}, got %d", n), http.StatusBadRequest) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - siw.ErrorHandler(c, fmt.Errorf("Header parameter {{ .Name }} is required, but not found"), http.StatusBadRequest) - return - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - { - var cookie string - if cookie, err = c.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{ .Name }}'"), http.StatusBadRequest) - return - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{ .Name }}' as JSON"), http.StatusBadRequest) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{ .Name }}: %w", err), http.StatusBadRequest) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandler(c, fmt.Errorf("Query argument {{ .Name }} is required, but not found"), http.StatusBadRequest) - return - }{{ end }} - } -{{ end }} -{{ end }} - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.{{ .GoOperationID }}(c{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl deleted file mode 100644 index 9d7bcf2121..0000000000 --- a/experimental/internal/codegen/templates/files/server/gorilla/handler.go.tmpl +++ /dev/null @@ -1,57 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Gorilla servers. - Input: []OperationDescriptor -*/ -}} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, GorillaServerOptions{}) -} - -// GorillaServerOptions configures the Gorilla server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -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) - } - } -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, - } -{{ end }} -{{- range . }} - r.HandleFunc(options.BaseURL+"{{ pathToGorillaPattern .Path }}", wrapper.{{ .GoOperationID }}).Methods("{{ .Method }}") -{{- end }} - return r -} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl deleted file mode 100644 index 7a9855b515..0000000000 --- a/experimental/internal/codegen/templates/files/server/gorilla/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Gorilla servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { - w.WriteHeader(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl deleted file mode 100644 index b0a24f0fdc..0000000000 --- a/experimental/internal/codegen/templates/files/server/gorilla/receiver.go.tmpl +++ /dev/null @@ -1,95 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Gorilla. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. -type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) - return - }{{ end }} -{{ end }} -{{- end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl deleted file mode 100644 index 395fea4d7b..0000000000 --- a/experimental/internal/codegen/templates/files/server/gorilla/wrapper.go.tmpl +++ /dev/null @@ -1,169 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Gorilla. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -{{ range . }} -// {{ .GoOperationID }} operation middleware -func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ if .PathParams }} - pathParams := mux.Vars(r) -{{ end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = pathParams["{{ .Name }}"] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(pathParams["{{ .Name }}"]), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, pathParams["{{ .Name }}"], &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{- if .Security }} - ctx := r.Context() -{{- range .Security }} - ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} - r = r.WithContext(ctx) -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := r.Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") - siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) - return - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - { - var cookie *http.Cookie - if cookie, err = r.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} - } -{{ end }} -{{ end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl deleted file mode 100644 index 2fa5813b49..0000000000 --- a/experimental/internal/codegen/templates/files/server/iris/handler.go.tmpl +++ /dev/null @@ -1,28 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for Iris servers. - Input: []OperationDescriptor -*/ -}} - -// IrisServerOptions is the option for iris server. -type IrisServerOptions struct { - BaseURL string - Middlewares []iris.Handler -} - -// 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) { -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - } -{{ end }} -{{- range . }} - router.{{ .Method | lower | title }}(options.BaseURL+"{{ pathToIrisPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} - router.Build() -} diff --git a/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl deleted file mode 100644 index 5b80fa550c..0000000000 --- a/experimental/internal/codegen/templates/files/server/iris/interface.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates the ServerInterface for Iris servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(ctx iris.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. -type Unimplemented struct{} - -{{- range . }} -{{ .SummaryAsComment }} -// ({{ .Method }} {{ .Path }}) -func (_ Unimplemented) {{ .GoOperationID }}(ctx iris.Context{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) { - ctx.StatusCode(http.StatusNotImplemented) -} -{{- end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl deleted file mode 100644 index 050076b4a4..0000000000 --- a/experimental/internal/codegen/templates/files/server/iris/receiver.go.tmpl +++ /dev/null @@ -1,84 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for Iris. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx iris.Context{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an iris.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface) iris.Handler { - return func(ctx iris.Context) { -{{- if .HasParams }} - var err error - _ = err - - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := ctx.URLParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString("Query parameter {{ .Name }} is required") - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.Request().URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList := ctx.Request().Header[http.CanonicalHeaderKey("{{ .Name }}")]; len(valueList) > 0 { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString(fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - return - } -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - ctx.StatusCode(http.StatusBadRequest) - _, _ = ctx.WriteString("Header parameter {{ .Name }} is required") - return - }{{ end }} -{{ end }} -{{- end }} - si.Handle{{ .GoOperationID }}{{ $.Prefix }}(ctx{{ if .HasParams }}, params{{ end }}) - } -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl deleted file mode 100644 index 8c44f3dd10..0000000000 --- a/experimental/internal/codegen/templates/files/server/iris/wrapper.go.tmpl +++ /dev/null @@ -1,160 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods for Iris. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts iris contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -{{ range . }} -// {{ .GoOperationID }} converts iris context to params. -func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx iris.Context) { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = ctx.Params().Get("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(ctx.Params().Get("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, ctx.Params().Get("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } -{{- end }} -{{ end }} -{{- if .Security }} -{{- range .Security }} - ctx.Values().Set({{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.Request().URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } -{{- else }} - if paramValue := ctx.URLParam("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString("Query argument {{ .Name }} is required, but not found") - return - }{{ end }} -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := ctx.Request().Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Expected one value for {{ .Name }}, got %d", n)) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString("Header {{ .Name }} is required, but not found") - return - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - if cookie := ctx.GetCookie("{{ .Name }}"); cookie != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Error unescaping cookie parameter '%s'", "{{ .Name }}")) - return - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Error unmarshaling parameter '%s' as JSON", "{{ .Name }}")) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie, &value) - if err != nil { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString(fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - ctx.StatusCode(http.StatusBadRequest) - ctx.WriteString("Cookie {{ .Name }} is required, but not found") - return - }{{ end }} -{{ end }} -{{ end }} - // Invoke the callback with all the unmarshaled arguments - w.Handler.{{ .GoOperationID }}(ctx{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/param_types.go.tmpl b/experimental/internal/codegen/templates/files/server/param_types.go.tmpl deleted file mode 100644 index 7b0eb914de..0000000000 --- a/experimental/internal/codegen/templates/files/server/param_types.go.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- /* - This template generates parameter struct types for server operations. - Input: []OperationDescriptor -*/ -}} - -{{ range . }} -{{- if .HasParams }} -// {{ .ParamsTypeName }} defines parameters for {{ .GoOperationID }}. -type {{ .ParamsTypeName }} struct { -{{- range .QueryParams }} - // {{ .Name }} {{ if .Required }}(required){{ else }}(optional){{ end }} - {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} `form:"{{ .Name }}" json:"{{ .Name }}"` -{{- end }} -{{- range .HeaderParams }} - // {{ .Name }} (header{{ if .Required }}, required{{ end }}) - {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} -{{- end }} -{{- range .CookieParams }} - // {{ .Name }} (cookie{{ if .Required }}, required{{ end }}) - {{ .GoName }} {{ if .HasOptionalPointer }}*{{ end }}{{ .TypeDecl }} -{{- end }} -} -{{ end }} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl deleted file mode 100644 index 47d50ec8bc..0000000000 --- a/experimental/internal/codegen/templates/files/server/stdhttp/handler.go.tmpl +++ /dev/null @@ -1,63 +0,0 @@ -{{- /* - This template generates the HTTP handler and routing for StdHTTP servers. - Input: []OperationDescriptor -*/ -}} - -// 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)) - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - -// StdHTTPServerOptions configures the StdHTTP server. -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, - }) -} - -// HandlerFromMuxWithBaseURL creates http.Handler with routing and a base URL. -func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{ - BaseURL: baseURL, - BaseRouter: m, - }) -} - -// HandlerWithOptions creates http.Handler with additional options. -func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { - m := options.BaseRouter - - if m == nil { - m = http.NewServeMux() - } - if options.ErrorHandlerFunc == nil { - options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } -{{ if . }} - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, - } -{{ end }} -{{- range . }} - m.HandleFunc("{{ .Method }} "+options.BaseURL+"{{ pathToStdHTTPPattern .Path }}", wrapper.{{ .GoOperationID }}) -{{- end }} - return m -} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl deleted file mode 100644 index 6dc320f8f7..0000000000 --- a/experimental/internal/codegen/templates/files/server/stdhttp/interface.go.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -{{- /* - This template generates the ServerInterface for StdHTTP servers. - Input: []OperationDescriptor -*/ -}} - -// ServerInterface represents all server handlers. -type ServerInterface interface { -{{- range . }} -{{ .SummaryAsComment }} - // ({{ .Method }} {{ .Path }}) - {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request{{ range .PathParams }}, {{ .GoVariableName }} {{ .TypeDecl }}{{ end }}{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl deleted file mode 100644 index 5f6d1fb5d0..0000000000 --- a/experimental/internal/codegen/templates/files/server/stdhttp/receiver.go.tmpl +++ /dev/null @@ -1,108 +0,0 @@ -{{- /* - This template generates the receiver interface and handler functions for StdHTTP. - Receiver handlers receive webhook/callback requests — the caller registers them at chosen paths. - Input: ReceiverTemplateData -*/ -}} - -// {{ .Prefix }}ReceiverInterface represents handlers for receiving {{ .PrefixLower }} requests. -type {{ .Prefix }}ReceiverInterface interface { -{{- range .Operations }} -{{ .SummaryAsComment }} - // Handle{{ .GoOperationID }}{{ $.Prefix }} handles the {{ .Method }} {{ $.PrefixLower }} request. - Handle{{ .GoOperationID }}{{ $.Prefix }}(w http.ResponseWriter, r *http.Request{{ if .HasParams }}, params {{ .ParamsTypeName }}{{ end }}) -{{- end }} -} - -// {{ .Prefix }}ReceiverMiddlewareFunc is a middleware function for {{ $.PrefixLower }} receiver handlers. -type {{ .Prefix }}ReceiverMiddlewareFunc func(http.Handler) http.Handler - -{{ range .Operations }} -// {{ .GoOperationID }}{{ $.Prefix }}Handler returns an http.Handler for the {{ .GoOperationID }} {{ $.PrefixLower }}. -// The caller is responsible for registering this handler at the appropriate path. -func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterface, errHandler func(w http.ResponseWriter, r *http.Request, err error), middlewares ...{{ $.Prefix }}ReceiverMiddlewareFunc) http.Handler { - if errHandler == nil { - errHandler = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -{{- if .HasParams }} - var err error - _ = err - - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ range .HeaderParams }} - if valueList, found := r.Header[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - errHandler(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - errHandler(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - errHandler(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: fmt.Errorf("header parameter {{ .Name }} is required, but not found")}) - return - }{{ end }} -{{ end }} -{{- end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - si.Handle{{ .GoOperationID }}{{ $.Prefix }}(w, r{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range middlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) - }) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl b/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl deleted file mode 100644 index 6c74e9c980..0000000000 --- a/experimental/internal/codegen/templates/files/server/stdhttp/wrapper.go.tmpl +++ /dev/null @@ -1,166 +0,0 @@ -{{- /* - This template generates the ServerInterfaceWrapper that extracts parameters - from HTTP requests and calls the ServerInterface methods. - Input: []OperationDescriptor -*/ -}} - -// ServerInterfaceWrapper converts HTTP requests to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// MiddlewareFunc is a middleware function type. -type MiddlewareFunc func(http.Handler) http.Handler - -{{ range . }} -// {{ .GoOperationID }} operation middleware -func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) { -{{- if or .PathParams .HasParams }} - var err error -{{- end }} -{{ range .PathParams }} - // ------------- Path parameter "{{ .Name }}" ------------- - var {{ .GoVariableName }} {{ .TypeDecl }} -{{ if .IsPassThrough }} - {{ .GoVariableName }} = r.PathValue("{{ .Name }}") -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(r.PathValue("{{ .Name }}")), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationPath, r.PathValue("{{ .Name }}"), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{- if .Security }} - ctx := r.Context() -{{- range .Security }} - ctx = context.WithValue(ctx, {{ .Name | toGoIdentifier }}Scopes, []string{ {{- range $i, $s := .Scopes }}{{ if $i }}, {{ end }}"{{ $s }}"{{ end -}} }) -{{- end }} - r = r.WithContext(ctx) -{{- end }} -{{ if .HasParams }} - // Parameter object where we will unmarshal all parameters from the context - var params {{ .ParamsTypeName }} -{{ range .QueryParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" ------------- -{{- if or .Required .IsPassThrough .IsJSON }} - if paramValue := r.URL.Query().Get("{{ .Name }}"); paramValue != "" { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}paramValue -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - err = json.Unmarshal([]byte(paramValue), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), ¶ms.{{ .GoName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{ end }} -{{ if .HeaderParams }} - headers := r.Header -{{ range .HeaderParams }} - // ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} header parameter "{{ .Name }}" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("{{ .Name }}")]; found { - var {{ .GoVariableName }} {{ .TypeDecl }} - n := len(valueList) - if n != 1 { - siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{ .Name }}", Count: n}) - return - } -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}valueList[0] -{{- end }} -{{- if .IsJSON }} - err = json.Unmarshal([]byte(valueList[0]), &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} -{{- if .IsStyled }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationHeader, valueList[0], &{{ .GoVariableName }}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } -{{- end }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}{{ .GoVariableName }} - }{{ if .Required }} else { - err := fmt.Errorf("Header parameter {{ .Name }} is required, but not found") - siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{ .Name }}", Err: err}) - return - }{{ end }} -{{ end }} -{{ end }} -{{ range .CookieParams }} - { - var cookie *http.Cookie - if cookie, err = r.Cookie("{{ .Name }}"); err == nil { -{{- if .IsPassThrough }} - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}cookie.Value -{{- end }} -{{- if .IsJSON }} - var value {{ .TypeDecl }} - decoded, err := url.QueryUnescape(cookie.Value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - err = json.Unmarshal([]byte(decoded), &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} -{{- if .IsStyled }} - var value {{ .TypeDecl }} - err = {{ .BindFunc }}("{{ .Name }}", ParamLocationCookie, cookie.Value, &value) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err}) - return - } - params.{{ .GoName }} = {{ if .HasOptionalPointer }}&{{ end }}value -{{- end }} - }{{ if .Required }} else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{ .Name }}"}) - return - }{{ end }} - } -{{ end }} -{{ end }} - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.{{ .GoOperationID }}(w, r{{ range .PathParams }}, {{ .GoVariableName }}{{ end }}{{ if .HasParams }}, params{{ end }}) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} -{{ end }} diff --git a/experimental/internal/codegen/templates/files/types/date.tmpl b/experimental/internal/codegen/templates/files/types/date.tmpl deleted file mode 100644 index 1698b09320..0000000000 --- a/experimental/internal/codegen/templates/files/types/date.tmpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* Date type for OpenAPI format: date */}} - -const DateFormat = "2006-01-02" - -type Date struct { - time.Time -} - -func (d Date) MarshalJSON() ([]byte, error) { - return json.Marshal(d.Format(DateFormat)) -} - -func (d *Date) UnmarshalJSON(data []byte) error { - var dateStr string - err := json.Unmarshal(data, &dateStr) - if err != nil { - return err - } - parsed, err := time.Parse(DateFormat, dateStr) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -func (d Date) String() string { - return d.Format(DateFormat) -} - -func (d *Date) UnmarshalText(data []byte) error { - parsed, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = parsed - return nil -} diff --git a/experimental/internal/codegen/templates/files/types/email.tmpl b/experimental/internal/codegen/templates/files/types/email.tmpl deleted file mode 100644 index 1f1e5d100a..0000000000 --- a/experimental/internal/codegen/templates/files/types/email.tmpl +++ /dev/null @@ -1,43 +0,0 @@ -{{/* Email type for OpenAPI format: email */}} - -const ( - emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" -) - -var ( - emailRegex = regexp.MustCompile(emailRegexString) -) - -// ErrValidationEmail is the sentinel error returned when an email fails validation -var ErrValidationEmail = errors.New("email: failed to pass regex validation") - -// Email represents an email address. -// It is a string type that must pass regex validation before being marshalled -// to JSON or unmarshalled from JSON. -type Email string - -func (e Email) MarshalJSON() ([]byte, error) { - if !emailRegex.MatchString(string(e)) { - return nil, ErrValidationEmail - } - - return json.Marshal(string(e)) -} - -func (e *Email) UnmarshalJSON(data []byte) error { - if e == nil { - return nil - } - - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - - *e = Email(s) - if !emailRegex.MatchString(s) { - return ErrValidationEmail - } - - return nil -} diff --git a/experimental/internal/codegen/templates/files/types/file.tmpl b/experimental/internal/codegen/templates/files/types/file.tmpl deleted file mode 100644 index 3b853101bb..0000000000 --- a/experimental/internal/codegen/templates/files/types/file.tmpl +++ /dev/null @@ -1,64 +0,0 @@ -{{/* File type for OpenAPI format: binary */}} - -type File struct { - multipart *multipart.FileHeader - data []byte - filename string -} - -func (file *File) InitFromMultipart(header *multipart.FileHeader) { - file.multipart = header - file.data = nil - file.filename = "" -} - -func (file *File) InitFromBytes(data []byte, filename string) { - file.data = data - file.filename = filename - file.multipart = nil -} - -func (file File) MarshalJSON() ([]byte, error) { - b, err := file.Bytes() - if err != nil { - return nil, err - } - return json.Marshal(b) -} - -func (file *File) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &file.data) -} - -func (file File) Bytes() ([]byte, error) { - if file.multipart != nil { - f, err := file.multipart.Open() - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return io.ReadAll(f) - } - return file.data, nil -} - -func (file File) Reader() (io.ReadCloser, error) { - if file.multipart != nil { - return file.multipart.Open() - } - return io.NopCloser(bytes.NewReader(file.data)), nil -} - -func (file File) Filename() string { - if file.multipart != nil { - return file.multipart.Filename - } - return file.filename -} - -func (file File) FileSize() int64 { - if file.multipart != nil { - return file.multipart.Size - } - return int64(len(file.data)) -} diff --git a/experimental/internal/codegen/templates/files/types/nullable.tmpl b/experimental/internal/codegen/templates/files/types/nullable.tmpl deleted file mode 100644 index cf75b0910c..0000000000 --- a/experimental/internal/codegen/templates/files/types/nullable.tmpl +++ /dev/null @@ -1,104 +0,0 @@ -{{/* Nullable type for OpenAPI nullable fields - implements three-state semantics: unspecified, null, or value */}} - -// Nullable is a generic type that can distinguish between: -// - Field not provided (unspecified) -// - Field explicitly set to null -// - Field has a value -// -// This is implemented as a map[bool]T where: -// - Empty map: unspecified -// - map[false]T: explicitly null -// - map[true]T: has a value -type Nullable[T any] map[bool]T - -// NewNullableWithValue creates a Nullable with the given value. -func NewNullableWithValue[T any](value T) Nullable[T] { - return Nullable[T]{true: value} -} - -// NewNullNullable creates a Nullable that is explicitly null. -func NewNullNullable[T any]() Nullable[T] { - return Nullable[T]{false: *new(T)} -} - -// Get returns the value if set, or an error if null or unspecified. -func (n Nullable[T]) Get() (T, error) { - if v, ok := n[true]; ok { - return v, nil - } - var zero T - if n.IsNull() { - return zero, ErrNullableIsNull - } - return zero, ErrNullableNotSpecified -} - -// MustGet returns the value or panics if null or unspecified. -func (n Nullable[T]) MustGet() T { - v, err := n.Get() - if err != nil { - panic(err) - } - return v -} - -// Set assigns a value. -func (n *Nullable[T]) Set(value T) { - *n = Nullable[T]{true: value} -} - -// SetNull marks the field as explicitly null. -func (n *Nullable[T]) SetNull() { - *n = Nullable[T]{false: *new(T)} -} - -// SetUnspecified clears the field (as if it was never set). -func (n *Nullable[T]) SetUnspecified() { - *n = nil -} - -// IsNull returns true if the field is explicitly null. -func (n Nullable[T]) IsNull() bool { - if n == nil { - return false - } - _, ok := n[false] - return ok -} - -// IsSpecified returns true if the field was provided (either null or a value). -func (n Nullable[T]) IsSpecified() bool { - return len(n) > 0 -} - -// MarshalJSON implements json.Marshaler. -func (n Nullable[T]) MarshalJSON() ([]byte, error) { - if n.IsNull() { - return []byte("null"), nil - } - if v, ok := n[true]; ok { - return json.Marshal(v) - } - // Unspecified - this shouldn't be called if omitempty is used correctly - return []byte("null"), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (n *Nullable[T]) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - n.SetNull() - return nil - } - var v T - if err := json.Unmarshal(data, &v); err != nil { - return err - } - n.Set(v) - return nil -} - -// ErrNullableIsNull is returned when trying to get a value from a null Nullable. -var ErrNullableIsNull = errors.New("nullable value is null") - -// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. -var ErrNullableNotSpecified = errors.New("nullable value is not specified") diff --git a/experimental/internal/codegen/templates/files/types/uuid.tmpl b/experimental/internal/codegen/templates/files/types/uuid.tmpl deleted file mode 100644 index f136f6a150..0000000000 --- a/experimental/internal/codegen/templates/files/types/uuid.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -{{/* UUID type for OpenAPI format: uuid */}} - -type UUID = uuid.UUID diff --git a/experimental/internal/codegen/templates/funcs.go b/experimental/internal/codegen/templates/funcs.go deleted file mode 100644 index b790f1702e..0000000000 --- a/experimental/internal/codegen/templates/funcs.go +++ /dev/null @@ -1,151 +0,0 @@ -package templates - -import ( - "regexp" - "strings" - "text/template" - - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -var titleCaser = cases.Title(language.English) - -// pathParamRE matches OpenAPI path parameters including styled variants. -// Matches: {param}, {param*}, {.param}, {.param*}, {;param}, {;param*}, {?param}, {?param*} -var pathParamRE = regexp.MustCompile(`{[.;?]?([^{}*]+)\*?}`) - -// Funcs returns the template function map for server templates. -func Funcs() template.FuncMap { - return template.FuncMap{ - "pathToStdHTTPPattern": PathToStdHTTPPattern, - "pathToChiPattern": PathToChiPattern, - "pathToEchoPattern": PathToEchoPattern, - "pathToGinPattern": PathToGinPattern, - "pathToGorillaPattern": PathToGorillaPattern, - "pathToFiberPattern": PathToFiberPattern, - "pathToIrisPattern": PathToIrisPattern, - "toGoIdentifier": ToGoIdentifier, - "lower": strings.ToLower, - "title": titleCaser.String, - } -} - -// PathToStdHTTPPattern converts an OpenAPI path template to a Go 1.22+ std http pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// StdHTTP: /users/{user_id}/posts/{post_id} -// Special case: "/" becomes "/{$}" to match only the root path. -func PathToStdHTTPPattern(path string) string { - // https://pkg.go.dev/net/http#hdr-Patterns-ServeMux - // The special wildcard {$} matches only the end of the URL. - if path == "/" { - return "/{$}" - } - return pathParamRE.ReplaceAllString(path, "{$1}") -} - -// PathToChiPattern converts an OpenAPI path template to a Chi-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Chi: /users/{user_id}/posts/{post_id} -func PathToChiPattern(path string) string { - return pathParamRE.ReplaceAllString(path, "{$1}") -} - -// PathToEchoPattern converts an OpenAPI path template to an Echo-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Echo: /users/:user_id/posts/:post_id -func PathToEchoPattern(path string) string { - return pathParamRE.ReplaceAllString(path, ":$1") -} - -// PathToGinPattern converts an OpenAPI path template to a Gin-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Gin: /users/:user_id/posts/:post_id -func PathToGinPattern(path string) string { - return pathParamRE.ReplaceAllString(path, ":$1") -} - -// PathToGorillaPattern converts an OpenAPI path template to a Gorilla Mux-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Gorilla: /users/{user_id}/posts/{post_id} -func PathToGorillaPattern(path string) string { - return pathParamRE.ReplaceAllString(path, "{$1}") -} - -// PathToFiberPattern converts an OpenAPI path template to a Fiber-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Fiber: /users/:user_id/posts/:post_id -func PathToFiberPattern(path string) string { - return pathParamRE.ReplaceAllString(path, ":$1") -} - -// PathToIrisPattern converts an OpenAPI path template to an Iris-compatible pattern. -// OpenAPI: /users/{user_id}/posts/{post_id} -// Iris: /users/:user_id/posts/:post_id -func PathToIrisPattern(path string) string { - return pathParamRE.ReplaceAllString(path, ":$1") -} - -// ToGoIdentifier converts a string to a valid Go identifier. -// This is a simple version for template usage. -func ToGoIdentifier(s string) string { - if s == "" { - return "Empty" - } - - // Replace non-alphanumeric characters with underscores - result := make([]byte, 0, len(s)) - capitalizeNext := true - - for i := 0; i < len(s); i++ { - c := s[i] - if c >= 'a' && c <= 'z' { - if capitalizeNext { - result = append(result, c-32) // uppercase - capitalizeNext = false - } else { - result = append(result, c) - } - } else if c >= 'A' && c <= 'Z' { - result = append(result, c) - capitalizeNext = false - } else if c >= '0' && c <= '9' { - result = append(result, c) - capitalizeNext = false - } else { - // Word separator - capitalizeNext = true - } - } - - if len(result) == 0 { - return "Empty" - } - - // Handle leading digit - if result[0] >= '0' && result[0] <= '9' { - result = append([]byte("N"), result...) - } - - str := string(result) - - // Handle Go keywords - lower := strings.ToLower(str) - if isGoKeyword(lower) { - str = str + "_" - } - - return str -} - -// isGoKeyword returns true if s is a Go keyword. -func isGoKeyword(s string) bool { - keywords := map[string]bool{ - "break": true, "case": true, "chan": true, "const": true, "continue": true, - "default": true, "defer": true, "else": true, "fallthrough": true, "for": true, - "func": true, "go": true, "goto": true, "if": true, "import": true, - "interface": true, "map": true, "package": true, "range": true, "return": true, - "select": true, "struct": true, "switch": true, "type": true, "var": true, - } - return keywords[s] -} diff --git a/experimental/internal/codegen/templates/registry.go b/experimental/internal/codegen/templates/registry.go deleted file mode 100644 index 94ae240769..0000000000 --- a/experimental/internal/codegen/templates/registry.go +++ /dev/null @@ -1,909 +0,0 @@ -package templates - -// Import represents a Go import with optional alias. -type Import struct { - Path string - Alias string // empty if no alias -} - -// TypeTemplate defines a template for a custom type along with its required imports. -type TypeTemplate struct { - Name string // Type name (e.g., "Email", "Date") - Imports []Import // Required imports for this type - Template string // Template name in embedded FS (e.g., "types/email.tmpl") -} - -// TypeTemplates maps type names to their template definitions. -var TypeTemplates = map[string]TypeTemplate{ - "Email": { - Name: "Email", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "regexp"}, - }, - Template: "types/email.tmpl", - }, - "Date": { - Name: "Date", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "time"}, - }, - Template: "types/date.tmpl", - }, - "UUID": { - Name: "UUID", - Imports: []Import{ - {Path: "github.com/google/uuid"}, - }, - Template: "types/uuid.tmpl", - }, - "File": { - Name: "File", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding/json"}, - {Path: "io"}, - {Path: "mime/multipart"}, - }, - Template: "types/file.tmpl", - }, - "Nullable": { - Name: "Nullable", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "errors"}, - }, - Template: "types/nullable.tmpl", - }, -} - -// ParamTemplate defines a template for a parameter styling/binding function. -type ParamTemplate struct { - Name string // Function name (e.g., "StyleSimpleParam") - Imports []Import // Required imports for this function - Template string // Template name in embedded FS (e.g., "params/style_simple.go.tmpl") -} - -// ParamHelpersTemplate is the template for shared helper functions. -// This is included whenever any param function is used. -var ParamHelpersTemplate = ParamTemplate{ - Name: "helpers", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "net/url"}, - {Path: "reflect"}, - {Path: "sort"}, - {Path: "strconv"}, - {Path: "strings"}, - {Path: "time"}, - {Path: "github.com/google/uuid"}, - }, - Template: "params/helpers.go.tmpl", -} - -// ParamTemplates maps style/explode combinations to their template definitions. -// Keys follow the pattern: "style_{style}" or "style_{style}_explode" for styling, -// and "bind_{style}" or "bind_{style}_explode" for binding. -var ParamTemplates = map[string]ParamTemplate{ - // Style templates (serialization) - "style_simple": { - Name: "StyleSimpleParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_simple.go.tmpl", - }, - "style_simple_explode": { - Name: "StyleSimpleExplodeParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_simple_explode.go.tmpl", - }, - "style_label": { - Name: "StyleLabelParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_label.go.tmpl", - }, - "style_label_explode": { - Name: "StyleLabelExplodeParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_label_explode.go.tmpl", - }, - "style_matrix": { - Name: "StyleMatrixParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_matrix.go.tmpl", - }, - "style_matrix_explode": { - Name: "StyleMatrixExplodeParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_matrix_explode.go.tmpl", - }, - "style_form": { - Name: "StyleFormParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_form.go.tmpl", - }, - "style_form_explode": { - Name: "StyleFormExplodeParam", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding"}, - {Path: "encoding/json"}, - {Path: "errors"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_form_explode.go.tmpl", - }, - "style_spaceDelimited": { - Name: "StyleSpaceDelimitedParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_space_delimited.go.tmpl", - }, - "style_spaceDelimited_explode": { - Name: "StyleSpaceDelimitedExplodeParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_space_delimited_explode.go.tmpl", - }, - "style_pipeDelimited": { - Name: "StylePipeDelimitedParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_pipe_delimited.go.tmpl", - }, - "style_pipeDelimited_explode": { - Name: "StylePipeDelimitedExplodeParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/style_pipe_delimited_explode.go.tmpl", - }, - "style_deepObject": { - Name: "StyleDeepObjectParam", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "sort"}, - {Path: "strconv"}, - {Path: "strings"}, - }, - Template: "params/style_deep_object.go.tmpl", - }, - - // Bind templates (deserialization) - "bind_simple": { - Name: "BindSimpleParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_simple.go.tmpl", - }, - "bind_simple_explode": { - Name: "BindSimpleExplodeParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_simple_explode.go.tmpl", - }, - "bind_label": { - Name: "BindLabelParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_label.go.tmpl", - }, - "bind_label_explode": { - Name: "BindLabelExplodeParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_label_explode.go.tmpl", - }, - "bind_matrix": { - Name: "BindMatrixParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_matrix.go.tmpl", - }, - "bind_matrix_explode": { - Name: "BindMatrixExplodeParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_matrix_explode.go.tmpl", - }, - "bind_form": { - Name: "BindFormParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_form.go.tmpl", - }, - "bind_form_explode": { - Name: "BindFormExplodeParam", - Imports: []Import{ - {Path: "fmt"}, - {Path: "net/url"}, - {Path: "reflect"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/bind_form_explode.go.tmpl", - }, - "bind_spaceDelimited": { - Name: "BindSpaceDelimitedParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_space_delimited.go.tmpl", - }, - "bind_spaceDelimited_explode": { - Name: "BindSpaceDelimitedExplodeParam", - Imports: []Import{ - {Path: "net/url"}, - }, - Template: "params/bind_space_delimited_explode.go.tmpl", - }, - "bind_pipeDelimited": { - Name: "BindPipeDelimitedParam", - Imports: []Import{ - {Path: "encoding"}, - {Path: "fmt"}, - {Path: "reflect"}, - {Path: "strings"}, - }, - Template: "params/bind_pipe_delimited.go.tmpl", - }, - "bind_pipeDelimited_explode": { - Name: "BindPipeDelimitedExplodeParam", - Imports: []Import{ - {Path: "net/url"}, - }, - Template: "params/bind_pipe_delimited_explode.go.tmpl", - }, - "bind_deepObject": { - Name: "BindDeepObjectParam", - Imports: []Import{ - {Path: "errors"}, - {Path: "fmt"}, - {Path: "net/url"}, - {Path: "reflect"}, - {Path: "sort"}, - {Path: "strconv"}, - {Path: "strings"}, - {Path: "time"}, - }, - Template: "params/bind_deep_object.go.tmpl", - }, -} - -// ParamStyleKey returns the registry key for a style/explode combination. -// The prefix should be "style_" for serialization or "bind_" for binding. -func ParamStyleKey(prefix, style string, explode bool) string { - key := prefix + style - if explode { - key += "_explode" - } - return key -} - -// ServerTemplate defines a template for server generation. -type ServerTemplate struct { - Name string // Template name (e.g., "interface", "handler") - Imports []Import // Required imports for this template - Template string // Template path in embedded FS -} - -// ReceiverTemplate defines a template for receiver (webhook/callback) generation. -type ReceiverTemplate struct { - Name string // Template name (e.g., "receiver") - Imports []Import // Required imports for this template - Template string // Template path in embedded FS -} - -// StdHTTPReceiverTemplates contains receiver templates for StdHTTP servers. -var StdHTTPReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "server/stdhttp/receiver.go.tmpl", - }, -} - -// ChiReceiverTemplates contains receiver templates for Chi servers. -var ChiReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "server/chi/receiver.go.tmpl", - }, -} - -// EchoReceiverTemplates contains receiver templates for Echo v5 servers. -var EchoReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/labstack/echo/v5"}, - }, - Template: "server/echo/receiver.go.tmpl", - }, -} - -// EchoV4ReceiverTemplates contains receiver templates for Echo v4 servers. -var EchoV4ReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/labstack/echo/v4"}, - }, - Template: "server/echo-v4/receiver.go.tmpl", - }, -} - -// GinReceiverTemplates contains receiver templates for Gin servers. -var GinReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/gin-gonic/gin"}, - }, - Template: "server/gin/receiver.go.tmpl", - }, -} - -// GorillaReceiverTemplates contains receiver templates for Gorilla servers. -var GorillaReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "server/gorilla/receiver.go.tmpl", - }, -} - -// FiberReceiverTemplates contains receiver templates for Fiber servers. -var FiberReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/gofiber/fiber/v3"}, - }, - Template: "server/fiber/receiver.go.tmpl", - }, -} - -// IrisReceiverTemplates contains receiver templates for Iris servers. -var IrisReceiverTemplates = map[string]ReceiverTemplate{ - "receiver": { - Name: "receiver", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/kataras/iris/v12"}, - }, - Template: "server/iris/receiver.go.tmpl", - }, -} - -// StdHTTPServerTemplates contains templates for StdHTTP server generation. -var StdHTTPServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - }, - Template: "server/stdhttp/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "net/http"}, - }, - Template: "server/stdhttp/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "server/stdhttp/wrapper.go.tmpl", - }, -} - -// ChiServerTemplates contains templates for Chi server generation. -var ChiServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - }, - Template: "server/chi/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/go-chi/chi/v5"}, - }, - Template: "server/chi/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/go-chi/chi/v5"}, - }, - Template: "server/chi/wrapper.go.tmpl", - }, -} - -// EchoServerTemplates contains templates for Echo v5 server generation. -var EchoServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/labstack/echo/v5"}, - }, - Template: "server/echo/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "github.com/labstack/echo/v5"}, - }, - Template: "server/echo/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/labstack/echo/v5"}, - }, - Template: "server/echo/wrapper.go.tmpl", - }, -} - -// EchoV4ServerTemplates contains templates for Echo v4 server generation. -var EchoV4ServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/labstack/echo/v4"}, - }, - Template: "server/echo-v4/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "github.com/labstack/echo/v4"}, - }, - Template: "server/echo-v4/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/labstack/echo/v4"}, - }, - Template: "server/echo-v4/wrapper.go.tmpl", - }, -} - -// GinServerTemplates contains templates for Gin server generation. -var GinServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/gin-gonic/gin"}, - }, - Template: "server/gin/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "github.com/gin-gonic/gin"}, - }, - Template: "server/gin/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/gin-gonic/gin"}, - }, - Template: "server/gin/wrapper.go.tmpl", - }, -} - -// GorillaServerTemplates contains templates for Gorilla server generation. -var GorillaServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - }, - Template: "server/gorilla/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/gorilla/mux"}, - }, - Template: "server/gorilla/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/gorilla/mux"}, - }, - Template: "server/gorilla/wrapper.go.tmpl", - }, -} - -// FiberServerTemplates contains templates for Fiber server generation. -var FiberServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "github.com/gofiber/fiber/v3"}, - }, - Template: "server/fiber/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "github.com/gofiber/fiber/v3"}, - }, - Template: "server/fiber/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/gofiber/fiber/v3"}, - }, - Template: "server/fiber/wrapper.go.tmpl", - }, -} - -// IrisServerTemplates contains templates for Iris server generation. -var IrisServerTemplates = map[string]ServerTemplate{ - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "net/http"}, - {Path: "github.com/kataras/iris/v12"}, - }, - Template: "server/iris/interface.go.tmpl", - }, - "handler": { - Name: "handler", - Imports: []Import{ - {Path: "github.com/kataras/iris/v12"}, - }, - Template: "server/iris/handler.go.tmpl", - }, - "wrapper": { - Name: "wrapper", - Imports: []Import{ - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "github.com/kataras/iris/v12"}, - }, - Template: "server/iris/wrapper.go.tmpl", - }, -} - -// SharedServerTemplates contains templates shared across all server implementations. -var SharedServerTemplates = map[string]ServerTemplate{ - "errors": { - Name: "errors", - Imports: []Import{ - {Path: "fmt"}, - }, - Template: "server/errors.go.tmpl", - }, - "param_types": { - Name: "param_types", - Imports: []Import{}, - Template: "server/param_types.go.tmpl", - }, -} - -// InitiatorTemplate defines a template for initiator (webhook/callback sender) generation. -type InitiatorTemplate struct { - Name string // Template name (e.g., "initiator_base", "initiator_interface") - Imports []Import // Required imports for this template - Template string // Template path in embedded FS -} - -// InitiatorTemplates contains templates for initiator generation. -// These are shared between webhook and callback initiators (parameterized by prefix). -var InitiatorTemplates = map[string]InitiatorTemplate{ - "initiator_base": { - Name: "initiator_base", - Imports: []Import{ - {Path: "context"}, - {Path: "net/http"}, - }, - Template: "initiator/base.go.tmpl", - }, - "initiator_interface": { - Name: "initiator_interface", - Imports: []Import{ - {Path: "context"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "initiator/interface.go.tmpl", - }, - "initiator_methods": { - Name: "initiator_methods", - Imports: []Import{ - {Path: "context"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "initiator/methods.go.tmpl", - }, - "initiator_request_builders": { - Name: "initiator_request_builders", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding/json"}, - {Path: "io"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "initiator/request_builders.go.tmpl", - }, - "initiator_simple": { - Name: "initiator_simple", - Imports: []Import{ - {Path: "context"}, - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "initiator/simple.go.tmpl", - }, -} - -// ClientTemplate defines a template for client generation. -type ClientTemplate struct { - Name string // Template name (e.g., "base", "interface") - Imports []Import // Required imports for this template - Template string // Template path in embedded FS -} - -// ClientTemplates contains templates for client generation. -var ClientTemplates = map[string]ClientTemplate{ - "base": { - Name: "base", - Imports: []Import{ - {Path: "context"}, - {Path: "net/http"}, - {Path: "net/url"}, - {Path: "strings"}, - }, - Template: "client/base.go.tmpl", - }, - "interface": { - Name: "interface", - Imports: []Import{ - {Path: "context"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "client/interface.go.tmpl", - }, - "methods": { - Name: "methods", - Imports: []Import{ - {Path: "context"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "client/methods.go.tmpl", - }, - "request_builders": { - Name: "request_builders", - Imports: []Import{ - {Path: "bytes"}, - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "io"}, - {Path: "net/http"}, - {Path: "net/url"}, - }, - Template: "client/request_builders.go.tmpl", - }, - "simple": { - Name: "simple", - Imports: []Import{ - {Path: "context"}, - {Path: "encoding/json"}, - {Path: "fmt"}, - {Path: "io"}, - {Path: "net/http"}, - }, - Template: "client/simple.go.tmpl", - }, -} diff --git a/experimental/internal/codegen/templates/test/types/date.gen.go b/experimental/internal/codegen/templates/test/types/date.gen.go deleted file mode 100644 index 37c30d3b98..0000000000 --- a/experimental/internal/codegen/templates/test/types/date.gen.go +++ /dev/null @@ -1,46 +0,0 @@ -// Code generated by gentypes. DO NOT EDIT. - -package types - -import ( - "encoding/json" - "time" -) - - -const DateFormat = "2006-01-02" - -type Date struct { - time.Time -} - -func (d Date) MarshalJSON() ([]byte, error) { - return json.Marshal(d.Format(DateFormat)) -} - -func (d *Date) UnmarshalJSON(data []byte) error { - var dateStr string - err := json.Unmarshal(data, &dateStr) - if err != nil { - return err - } - parsed, err := time.Parse(DateFormat, dateStr) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -func (d Date) String() string { - return d.Format(DateFormat) -} - -func (d *Date) UnmarshalText(data []byte) error { - parsed, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = parsed - return nil -} diff --git a/experimental/internal/codegen/templates/test/types/date_test.go b/experimental/internal/codegen/templates/test/types/date_test.go deleted file mode 100644 index 211776522f..0000000000 --- a/experimental/internal/codegen/templates/test/types/date_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestDate_MarshalJSON(t *testing.T) { - testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) - b := struct { - DateField Date `json:"date"` - }{ - DateField: Date{testDate}, - } - jsonBytes, err := json.Marshal(b) - assert.NoError(t, err) - assert.JSONEq(t, `{"date":"2019-04-01"}`, string(jsonBytes)) -} - -func TestDate_UnmarshalJSON(t *testing.T) { - testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) - jsonStr := `{"date":"2019-04-01"}` - b := struct { - DateField Date `json:"date"` - }{} - err := json.Unmarshal([]byte(jsonStr), &b) - assert.NoError(t, err) - assert.Equal(t, testDate, b.DateField.Time) -} - -func TestDate_Stringer(t *testing.T) { - t.Run("nil date", func(t *testing.T) { - var d *Date - assert.Equal(t, "", fmt.Sprintf("%v", d)) - }) - - t.Run("ptr date", func(t *testing.T) { - d := &Date{ - Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), - } - assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d)) - }) - - t.Run("value date", func(t *testing.T) { - d := Date{ - Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), - } - assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d)) - }) -} - -func TestDate_UnmarshalText(t *testing.T) { - testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC) - value := []byte("2022-06-14") - - date := Date{} - err := date.UnmarshalText(value) - - assert.NoError(t, err) - assert.Equal(t, testDate, date.Time) -} diff --git a/experimental/internal/codegen/templates/test/types/email.gen.go b/experimental/internal/codegen/templates/test/types/email.gen.go deleted file mode 100644 index 6db0d58270..0000000000 --- a/experimental/internal/codegen/templates/test/types/email.gen.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by gentypes. DO NOT EDIT. - -package types - -import ( - "encoding/json" - "errors" - "regexp" -) - - -const ( - emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" -) - -var ( - emailRegex = regexp.MustCompile(emailRegexString) -) - -// ErrValidationEmail is the sentinel error returned when an email fails validation -var ErrValidationEmail = errors.New("email: failed to pass regex validation") - -// Email represents an email address. -// It is a string type that must pass regex validation before being marshalled -// to JSON or unmarshalled from JSON. -type Email string - -func (e Email) MarshalJSON() ([]byte, error) { - if !emailRegex.MatchString(string(e)) { - return nil, ErrValidationEmail - } - - return json.Marshal(string(e)) -} - -func (e *Email) UnmarshalJSON(data []byte) error { - if e == nil { - return nil - } - - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - - *e = Email(s) - if !emailRegex.MatchString(s) { - return ErrValidationEmail - } - - return nil -} diff --git a/experimental/internal/codegen/templates/test/types/email_test.go b/experimental/internal/codegen/templates/test/types/email_test.go deleted file mode 100644 index 736056b172..0000000000 --- a/experimental/internal/codegen/templates/test/types/email_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package types - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestEmail_MarshalJSON_Validation(t *testing.T) { - type requiredEmail struct { - EmailField Email `json:"email"` - } - - testCases := map[string]struct { - email Email - expectedJSON []byte - expectedError error - }{ - "it should succeed marshalling a valid email and return valid JSON populated with the email": { - email: Email("validemail@openapicodegen.com"), - expectedJSON: []byte(`{"email":"validemail@openapicodegen.com"}`), - expectedError: nil, - }, - "it should fail marshalling an invalid email and return a validation error": { - email: Email("invalidemail"), - expectedJSON: nil, - expectedError: ErrValidationEmail, - }, - "it should fail marshalling an empty email and return a validation error": { - email: Email(""), - expectedJSON: nil, - expectedError: ErrValidationEmail, - }, - } - - for name, tc := range testCases { - tc := tc - t.Run(name, func(t *testing.T) { - t.Parallel() - - jsonBytes, err := json.Marshal(requiredEmail{EmailField: tc.email}) - - if tc.expectedError != nil { - assert.ErrorIs(t, err, tc.expectedError) - } else { - assert.JSONEq(t, string(tc.expectedJSON), string(jsonBytes)) - } - }) - } -} - -func TestEmail_UnmarshalJSON_RequiredEmail_Validation(t *testing.T) { - type requiredEmail struct { - EmailField Email `json:"email"` - } - - requiredEmailTestCases := map[string]struct { - jsonStr string - expectedEmail Email - expectedError error - }{ - "it should succeed validating a valid email during the unmarshal process": { - jsonStr: `{"email":"gaben@valvesoftware.com"}`, - expectedError: nil, - expectedEmail: func() Email { - e := Email("gaben@valvesoftware.com") - return e - }(), - }, - "it should fail validating an invalid email": { - jsonStr: `{"email":"not-an-email"}`, - expectedError: ErrValidationEmail, - expectedEmail: func() Email { - e := Email("not-an-email") - return e - }(), - }, - "it should fail validating an empty email": { - jsonStr: `{"email":""}`, - expectedEmail: func() Email { - e := Email("") - return e - }(), - expectedError: ErrValidationEmail, - }, - "it should fail validating a null email": { - jsonStr: `{"email":null}`, - expectedEmail: func() Email { - e := Email("") - return e - }(), - expectedError: ErrValidationEmail, - }, - } - - for name, tc := range requiredEmailTestCases { - tc := tc - t.Run(name, func(t *testing.T) { - t.Parallel() - - b := requiredEmail{} - err := json.Unmarshal([]byte(tc.jsonStr), &b) - assert.Equal(t, tc.expectedEmail, b.EmailField) - assert.ErrorIs(t, err, tc.expectedError) - }) - } - -} - -func TestEmail_UnmarshalJSON_NullableEmail_Validation(t *testing.T) { - - type nullableEmail struct { - EmailField *Email `json:"email,omitempty"` - } - - nullableEmailTestCases := map[string]struct { - body nullableEmail - jsonStr string - expectedEmail *Email - expectedError error - }{ - "it should succeed validating a valid email during the unmarshal process": { - body: nullableEmail{}, - jsonStr: `{"email":"gaben@valvesoftware.com"}`, - expectedError: nil, - expectedEmail: func() *Email { - e := Email("gaben@valvesoftware.com") - return &e - }(), - }, - "it should fail validating an invalid email": { - body: nullableEmail{}, - jsonStr: `{"email":"not-an-email"}`, - expectedError: ErrValidationEmail, - expectedEmail: func() *Email { - e := Email("not-an-email") - return &e - }(), - }, - "it should fail validating an empty email": { - body: nullableEmail{}, - jsonStr: `{"email":""}`, - expectedError: ErrValidationEmail, - expectedEmail: func() *Email { - e := Email("") - return &e - }(), - }, - "it should succeed validating a null email": { - body: nullableEmail{}, - jsonStr: `{"email":null}`, - expectedEmail: nil, - expectedError: nil, - }, - "it should succeed validating a missing email": { - body: nullableEmail{}, - jsonStr: `{}`, - expectedEmail: nil, - expectedError: nil, - }, - } - - for name, tc := range nullableEmailTestCases { - tc := tc - t.Run(name, func(t *testing.T) { - t.Parallel() - - err := json.Unmarshal([]byte(tc.jsonStr), &tc.body) - assert.Equal(t, tc.expectedEmail, tc.body.EmailField) - if tc.expectedError != nil { - assert.ErrorIs(t, err, tc.expectedError) - } - }) - } -} diff --git a/experimental/internal/codegen/templates/test/types/file.gen.go b/experimental/internal/codegen/templates/test/types/file.gen.go deleted file mode 100644 index 391c94a9da..0000000000 --- a/experimental/internal/codegen/templates/test/types/file.gen.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by gentypes. DO NOT EDIT. - -package types - -import ( - "bytes" - "encoding/json" - "io" - "mime/multipart" -) - - -type File struct { - multipart *multipart.FileHeader - data []byte - filename string -} - -func (file *File) InitFromMultipart(header *multipart.FileHeader) { - file.multipart = header - file.data = nil - file.filename = "" -} - -func (file *File) InitFromBytes(data []byte, filename string) { - file.data = data - file.filename = filename - file.multipart = nil -} - -func (file File) MarshalJSON() ([]byte, error) { - b, err := file.Bytes() - if err != nil { - return nil, err - } - return json.Marshal(b) -} - -func (file *File) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &file.data) -} - -func (file File) Bytes() ([]byte, error) { - if file.multipart != nil { - f, err := file.multipart.Open() - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return io.ReadAll(f) - } - return file.data, nil -} - -func (file File) Reader() (io.ReadCloser, error) { - if file.multipart != nil { - return file.multipart.Open() - } - return io.NopCloser(bytes.NewReader(file.data)), nil -} - -func (file File) Filename() string { - if file.multipart != nil { - return file.multipart.Filename - } - return file.filename -} - -func (file File) FileSize() int64 { - if file.multipart != nil { - return file.multipart.Size - } - return int64(len(file.data)) -} diff --git a/experimental/internal/codegen/templates/test/types/file_test.go b/experimental/internal/codegen/templates/test/types/file_test.go deleted file mode 100644 index fb4ce98ae1..0000000000 --- a/experimental/internal/codegen/templates/test/types/file_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var _ json.Marshaler = (*File)(nil) -var _ json.Unmarshaler = (*File)(nil) - -func TestFileJSON(t *testing.T) { - type Object struct { - BinaryField File `json:"binary_field"` - } - - // Check whether we encode JSON properly. - var o Object - o.BinaryField.InitFromBytes([]byte("hello"), "") - buf, err := json.Marshal(o) - require.NoError(t, err) - t.Log(string(buf)) - - // Decode the same object back into File, ensure result is correct. - var o2 Object - err = json.Unmarshal(buf, &o2) - require.NoError(t, err) - o2Bytes, err := o2.BinaryField.Bytes() - require.NoError(t, err) - assert.Equal(t, []byte("hello"), o2Bytes) - - // Ensure it also works via pointer. - type Object2 struct { - BinaryFieldPtr *File `json:"binary_field"` - } - - var o3 Object2 - var f File - f.InitFromBytes([]byte("hello"), "") - o3.BinaryFieldPtr = &f - buf, err = json.Marshal(o) - require.NoError(t, err) - t.Log(string(buf)) - - var o4 Object2 - err = json.Unmarshal(buf, &o4) - require.NoError(t, err) - o4Bytes, err := o4.BinaryFieldPtr.Bytes() - require.NoError(t, err) - assert.Equal(t, []byte("hello"), o4Bytes) - -} diff --git a/experimental/internal/codegen/templates/test/types/generate.go b/experimental/internal/codegen/templates/test/types/generate.go deleted file mode 100644 index bab32084c7..0000000000 --- a/experimental/internal/codegen/templates/test/types/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package types - -//go:generate go run ./gentypes -package types -output . Email Date UUID File diff --git a/experimental/internal/codegen/templates/test/types/gentypes/main.go b/experimental/internal/codegen/templates/test/types/gentypes/main.go deleted file mode 100644 index c22eee2751..0000000000 --- a/experimental/internal/codegen/templates/test/types/gentypes/main.go +++ /dev/null @@ -1,109 +0,0 @@ -// gentypes generates Go type files from templates. -// Usage: gentypes -package -output [types...] -// -// Example: -// -// //go:generate gentypes -package types -output . Email Date UUID File -package main - -import ( - "bytes" - "flag" - "fmt" - "os" - "path/filepath" - "strings" - "text/template" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/templates" -) - -func main() { - packageName := flag.String("package", "", "Go package name for generated files") - outputDir := flag.String("output", ".", "output directory for generated files") - flag.Parse() - - if *packageName == "" { - fmt.Fprintln(os.Stderr, "error: -package is required") - os.Exit(1) - } - - typeNames := flag.Args() - if len(typeNames) == 0 { - fmt.Fprintln(os.Stderr, "error: at least one type name required") - fmt.Fprintln(os.Stderr, "available types: Email, Date, UUID, File") - os.Exit(1) - } - - for _, typeName := range typeNames { - if err := generateType(*packageName, *outputDir, typeName); err != nil { - fmt.Fprintf(os.Stderr, "error generating %s: %v\n", typeName, err) - os.Exit(1) - } - } -} - -func generateType(packageName, outputDir, typeName string) error { - tt, ok := templates.TypeTemplates[typeName] - if !ok { - return fmt.Errorf("unknown type: %s", typeName) - } - - // Read template content - tmplPath := "files/" + tt.Template - tmplContent, err := templates.TemplateFS.ReadFile(tmplPath) - if err != nil { - return fmt.Errorf("reading template %s: %w", tmplPath, err) - } - - // Parse and execute template (in case it has any directives) - tmpl, err := template.New(typeName).Parse(string(tmplContent)) - if err != nil { - return fmt.Errorf("parsing template: %w", err) - } - - var body bytes.Buffer - if err := tmpl.Execute(&body, nil); err != nil { - return fmt.Errorf("executing template: %w", err) - } - - // Build the output file - var out bytes.Buffer - - // Package declaration - fmt.Fprintf(&out, "// Code generated by gentypes. DO NOT EDIT.\n\n") - fmt.Fprintf(&out, "package %s\n", packageName) - - // Imports - if len(tt.Imports) > 0 { - out.WriteString("\nimport (\n") - for _, imp := range tt.Imports { - if imp.Alias != "" { - fmt.Fprintf(&out, "\t%s %q\n", imp.Alias, imp.Path) - } else { - fmt.Fprintf(&out, "\t%q\n", imp.Path) - } - } - out.WriteString(")\n") - } - - // Template body (skip the leading template comment if present) - bodyStr := body.String() - if strings.HasPrefix(bodyStr, "{{/*") { - // Skip the comment line - if idx := strings.Index(bodyStr, "*/}}"); idx != -1 { - bodyStr = bodyStr[idx+4:] - } - } - out.WriteString(bodyStr) - - // Write output file - filename := strings.ToLower(typeName) + ".gen.go" - outputPath := filepath.Join(outputDir, filename) - if err := os.WriteFile(outputPath, out.Bytes(), 0644); err != nil { - return fmt.Errorf("writing %s: %w", outputPath, err) - } - - fmt.Printf("generated %s\n", outputPath) - return nil -} diff --git a/experimental/internal/codegen/templates/test/types/uuid.gen.go b/experimental/internal/codegen/templates/test/types/uuid.gen.go deleted file mode 100644 index f1c45b3c36..0000000000 --- a/experimental/internal/codegen/templates/test/types/uuid.gen.go +++ /dev/null @@ -1,10 +0,0 @@ -// Code generated by gentypes. DO NOT EDIT. - -package types - -import ( - "github.com/google/uuid" -) - - -type UUID = uuid.UUID diff --git a/experimental/internal/codegen/templates/test/types/uuid_test.go b/experimental/internal/codegen/templates/test/types/uuid_test.go deleted file mode 100644 index bb62040b6c..0000000000 --- a/experimental/internal/codegen/templates/test/types/uuid_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package types - -import ( - "encoding/json" - "testing" - - "github.com/google/uuid" - "github.com/stretchr/testify/assert" -) - -func TestUUID_MarshalJSON_Zero(t *testing.T) { - var testUUID UUID - b := struct { - UUIDField UUID `json:"uuid"` - }{ - UUIDField: testUUID, - } - marshaled, err := json.Marshal(b) - assert.NoError(t, err) - assert.JSONEq(t, `{"uuid":"00000000-0000-0000-0000-000000000000"}`, string(marshaled)) -} - -func TestUUID_MarshalJSON_Pass(t *testing.T) { - testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002") - b := struct { - UUIDField UUID `json:"uuid"` - }{ - UUIDField: testUUID, - } - jsonBytes, err := json.Marshal(b) - assert.NoError(t, err) - assert.JSONEq(t, `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}`, string(jsonBytes)) -} - -func TestUUID_UnmarshalJSON_Fail(t *testing.T) { - jsonStr := `{"uuid":"this-is-not-a-uuid"}` - b := struct { - UUIDField UUID `json:"uuid"` - }{} - err := json.Unmarshal([]byte(jsonStr), &b) - assert.Error(t, err) -} - -func TestUUID_UnmarshalJSON_Pass(t *testing.T) { - testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002") - jsonStr := `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}` - b := struct { - UUIDField UUID `json:"uuid"` - }{} - err := json.Unmarshal([]byte(jsonStr), &b) - assert.NoError(t, err) - assert.Equal(t, testUUID, b.UUIDField) -} diff --git a/experimental/internal/codegen/test/comprehensive/doc.go b/experimental/internal/codegen/test/comprehensive/doc.go deleted file mode 100644 index 658e592917..0000000000 --- a/experimental/internal/codegen/test/comprehensive/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -package comprehensive - -//go:generate go run ../../../../cmd/oapi-codegen -package output -output output/comprehensive.gen.go ../files/comprehensive.yaml diff --git a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go b/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go deleted file mode 100644 index 633aa2dbe7..0000000000 --- a/experimental/internal/codegen/test/comprehensive/output/comprehensive.gen.go +++ /dev/null @@ -1,2098 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "mime/multipart" - "regexp" - "strings" - "sync" - "time" - - "github.com/google/uuid" -) - -// #/components/schemas/AllTypesRequired -type AllTypesRequired struct { - IntField int `json:"intField" form:"intField"` - Int32Field int32 `json:"int32Field" form:"int32Field"` - Int64Field int64 `json:"int64Field" form:"int64Field"` - FloatField float32 `json:"floatField" form:"floatField"` - DoubleField float64 `json:"doubleField" form:"doubleField"` - NumberField float32 `json:"numberField" form:"numberField"` - StringField string `json:"stringField" form:"stringField"` - BoolField bool `json:"boolField" form:"boolField"` - DateField Date `json:"dateField" form:"dateField"` - DateTimeField time.Time `json:"dateTimeField" form:"dateTimeField"` - UUIDField UUID `json:"uuidField" form:"uuidField"` - EmailField Email `json:"emailField" form:"emailField"` - URIField string `json:"uriField" form:"uriField"` - HostnameField string `json:"hostnameField" form:"hostnameField"` - Ipv4Field string `json:"ipv4Field" form:"ipv4Field"` - Ipv6Field string `json:"ipv6Field" form:"ipv6Field"` - ByteField []byte `json:"byteField" form:"byteField"` - BinaryField File `json:"binaryField" form:"binaryField"` - PasswordField string `json:"passwordField" form:"passwordField"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllTypesRequired) ApplyDefaults() { -} - -// #/components/schemas/AllTypesOptional -type AllTypesOptional struct { - IntField *int `json:"intField,omitempty" form:"intField,omitempty"` - Int32Field *int32 `json:"int32Field,omitempty" form:"int32Field,omitempty"` - Int64Field *int64 `json:"int64Field,omitempty" form:"int64Field,omitempty"` - FloatField *float32 `json:"floatField,omitempty" form:"floatField,omitempty"` - DoubleField *float64 `json:"doubleField,omitempty" form:"doubleField,omitempty"` - NumberField *float32 `json:"numberField,omitempty" form:"numberField,omitempty"` - StringField *string `json:"stringField,omitempty" form:"stringField,omitempty"` - BoolField *bool `json:"boolField,omitempty" form:"boolField,omitempty"` - DateField *Date `json:"dateField,omitempty" form:"dateField,omitempty"` - DateTimeField *time.Time `json:"dateTimeField,omitempty" form:"dateTimeField,omitempty"` - UUIDField *UUID `json:"uuidField,omitempty" form:"uuidField,omitempty"` - EmailField *Email `json:"emailField,omitempty" form:"emailField,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllTypesOptional) ApplyDefaults() { -} - -// #/components/schemas/NullableRequired -type NullableRequired struct { - NullableString Nullable[string] `json:"nullableString" form:"nullableString"` - NullableInt Nullable[int] `json:"nullableInt" form:"nullableInt"` - NullableObject Nullable[NullableRequiredNullableObject] `json:"nullableObject" form:"nullableObject"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NullableRequired) ApplyDefaults() { -} - -// #/components/schemas/NullableRequired/properties/nullableObject -type NullableRequiredNullableObject struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NullableRequiredNullableObject) ApplyDefaults() { -} - -// #/components/schemas/NullableOptional -type NullableOptional struct { - NullableString Nullable[string] `json:"nullableString,omitempty" form:"nullableString,omitempty"` - NullableInt Nullable[int] `json:"nullableInt,omitempty" form:"nullableInt,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NullableOptional) ApplyDefaults() { -} - -// #/components/schemas/ArrayTypes -type ArrayTypes struct { - StringArray []string `json:"stringArray,omitempty" form:"stringArray,omitempty"` - IntArray []int `json:"intArray,omitempty" form:"intArray,omitempty"` - ObjectArray []SimpleObject `json:"objectArray,omitempty" form:"objectArray,omitempty"` - InlineObjectArray []ArrayTypesInlineObjectArrayItem `json:"inlineObjectArray,omitempty" form:"inlineObjectArray,omitempty"` - NestedArray [][]string `json:"nestedArray,omitempty" form:"nestedArray,omitempty"` - NullableArray []string `json:"nullableArray,omitempty" form:"nullableArray,omitempty"` - ArrayWithConstraints []string `json:"arrayWithConstraints,omitempty" form:"arrayWithConstraints,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ArrayTypes) ApplyDefaults() { -} - -// #/components/schemas/ArrayTypes/properties/objectArray -type ArrayTypesObjectArray = []SimpleObject - -// #/components/schemas/ArrayTypes/properties/inlineObjectArray -type ArrayTypesInlineObjectArray = []ArrayTypesInlineObjectArrayItem - -// #/components/schemas/ArrayTypes/properties/inlineObjectArray/items -type ArrayTypesInlineObjectArrayItem struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ArrayTypesInlineObjectArrayItem) ApplyDefaults() { -} - -// #/components/schemas/SimpleObject -type SimpleObject struct { - ID int `json:"id" form:"id"` - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *SimpleObject) ApplyDefaults() { -} - -// #/components/schemas/NestedObject -type NestedObject struct { - Outer *NestedObjectOuter `json:"outer,omitempty" form:"outer,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NestedObject) ApplyDefaults() { - if s.Outer != nil { - s.Outer.ApplyDefaults() - } -} - -// #/components/schemas/NestedObject/properties/outer -type NestedObjectOuter struct { - Inner *NestedObjectOuterInner `json:"inner,omitempty" form:"inner,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NestedObjectOuter) ApplyDefaults() { - if s.Inner != nil { - s.Inner.ApplyDefaults() - } -} - -// #/components/schemas/NestedObject/properties/outer/properties/inner -type NestedObjectOuterInner struct { - Value *string `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NestedObjectOuterInner) ApplyDefaults() { -} - -// #/components/schemas/AdditionalPropsAny -type AdditionalPropsAny = map[string]any - -// #/components/schemas/AdditionalPropsNone -type AdditionalPropsNone struct { - Known *string `json:"known,omitempty" form:"known,omitempty"` - AdditionalProperties map[string]any `json:"-"` -} - -func (s AdditionalPropsNone) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if s.Known != nil { - result["known"] = s.Known - } - - // Add additional properties - for k, v := range s.AdditionalProperties { - result[k] = v - } - - return json.Marshal(result) -} - -func (s *AdditionalPropsNone) UnmarshalJSON(data []byte) error { - // Known fields - knownFields := map[string]bool{ - "known": true, - } - - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["known"]; ok { - var val string - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.Known = &val - } - - // Collect additional properties - s.AdditionalProperties = make(map[string]any) - for k, v := range raw { - if !knownFields[k] { - var val any - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.AdditionalProperties[k] = val - } - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AdditionalPropsNone) ApplyDefaults() { -} - -// #/components/schemas/AdditionalPropsTyped -type AdditionalPropsTyped = map[string]int - -// #/components/schemas/AdditionalPropsObject -type AdditionalPropsObject = map[string]any - -// #/components/schemas/AdditionalPropsWithProps -type AdditionalPropsWithProps struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -func (s AdditionalPropsWithProps) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if s.ID != nil { - result["id"] = s.ID - } - - // Add additional properties - for k, v := range s.AdditionalProperties { - result[k] = v - } - - return json.Marshal(result) -} - -func (s *AdditionalPropsWithProps) UnmarshalJSON(data []byte) error { - // Known fields - knownFields := map[string]bool{ - "id": true, - } - - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["id"]; ok { - var val int - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.ID = &val - } - - // Collect additional properties - s.AdditionalProperties = make(map[string]string) - for k, v := range raw { - if !knownFields[k] { - var val string - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.AdditionalProperties[k] = val - } - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AdditionalPropsWithProps) ApplyDefaults() { -} - -// #/components/schemas/StringEnum -type StringEnum string - -const ( - StringEnum_value1 StringEnum = "value1" - StringEnum_value2 StringEnum = "value2" - StringEnum_value3 StringEnum = "value3" -) - -// #/components/schemas/IntegerEnum -type IntegerEnum int - -const ( - IntegerEnum_N1 IntegerEnum = 1 - IntegerEnum_N2 IntegerEnum = 2 - IntegerEnum_N3 IntegerEnum = 3 -) - -// #/components/schemas/ObjectWithEnum -type ObjectWithEnum struct { - Status *string `json:"status,omitempty" form:"status,omitempty"` - Priority *int `json:"priority,omitempty" form:"priority,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithEnum) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithEnum/properties/status -type ObjectWithEnumStatus string - -const ( - ObjectWithEnumStatus_pending ObjectWithEnumStatus = "pending" - ObjectWithEnumStatus_active ObjectWithEnumStatus = "active" - ObjectWithEnumStatus_completed ObjectWithEnumStatus = "completed" -) - -// #/components/schemas/ObjectWithEnum/properties/priority -type ObjectWithEnumPriority int - -const ( - ObjectWithEnumPriority_N1 ObjectWithEnumPriority = 1 - ObjectWithEnumPriority_N2 ObjectWithEnumPriority = 2 - ObjectWithEnumPriority_N3 ObjectWithEnumPriority = 3 -) - -// #/components/schemas/InlineEnumInProperty -type InlineEnumInProperty struct { - InlineStatus *string `json:"inlineStatus,omitempty" form:"inlineStatus,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *InlineEnumInProperty) ApplyDefaults() { -} - -// #/components/schemas/InlineEnumInProperty/properties/inlineStatus -type InlineEnumInPropertyInlineStatus string - -const ( - InlineEnumInPropertyInlineStatus_on InlineEnumInPropertyInlineStatus = "on" - InlineEnumInPropertyInlineStatus_off InlineEnumInPropertyInlineStatus = "off" -) - -// #/components/schemas/BaseProperties -type BaseProperties struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *BaseProperties) ApplyDefaults() { -} - -// #/components/schemas/ExtendedObject -type ExtendedObject struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Name string `json:"name" form:"name"` - Description *string `json:"description,omitempty" form:"description,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ExtendedObject) ApplyDefaults() { -} - -// #/components/schemas/DeepInheritance -type DeepInheritance struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Name string `json:"name" form:"name"` - Description *string `json:"description,omitempty" form:"description,omitempty"` - Extra *string `json:"extra,omitempty" form:"extra,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DeepInheritance) ApplyDefaults() { -} - -// #/components/schemas/AllOfMultipleRefs -type AllOfMultipleRefs struct { - ID int `json:"id" form:"id"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Name *string `json:"name,omitempty" form:"name,omitempty"` - Merged *bool `json:"merged,omitempty" form:"merged,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfMultipleRefs) ApplyDefaults() { -} - -// #/components/schemas/AllOfInlineOnly -type AllOfInlineOnly struct { - First *string `json:"first,omitempty" form:"first,omitempty"` - Second *int `json:"second,omitempty" form:"second,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfInlineOnly) ApplyDefaults() { -} - -// #/components/schemas/AnyOfPrimitives -type AnyOfPrimitives struct { - String0 *string - Int1 *int -} - -func (u AnyOfPrimitives) MarshalJSON() ([]byte, error) { - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.Int1 != nil { - return json.Marshal(u.Int1) - } - return []byte("null"), nil -} - -func (u *AnyOfPrimitives) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 int - if err := json.Unmarshal(data, &v1); err == nil { - u.Int1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AnyOfPrimitives) ApplyDefaults() { -} - -// #/components/schemas/AnyOfObjects -type AnyOfObjects struct { - SimpleObject *SimpleObject - BaseProperties *BaseProperties -} - -func (u AnyOfObjects) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.SimpleObject != nil { - data, err := json.Marshal(u.SimpleObject) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.BaseProperties != nil { - data, err := json.Marshal(u.BaseProperties) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *AnyOfObjects) UnmarshalJSON(data []byte) error { - var v0 SimpleObject - if err := json.Unmarshal(data, &v0); err == nil { - u.SimpleObject = &v0 - } - - var v1 BaseProperties - if err := json.Unmarshal(data, &v1); err == nil { - u.BaseProperties = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AnyOfObjects) ApplyDefaults() { - if u.SimpleObject != nil { - u.SimpleObject.ApplyDefaults() - } - if u.BaseProperties != nil { - u.BaseProperties.ApplyDefaults() - } -} - -// #/components/schemas/AnyOfMixed -type AnyOfMixed struct { - String0 *string - SimpleObject *SimpleObject - AnyOfMixedAnyOf2 *AnyOfMixedAnyOf2 -} - -func (u AnyOfMixed) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.SimpleObject != nil { - data, err := json.Marshal(u.SimpleObject) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.AnyOfMixedAnyOf2 != nil { - data, err := json.Marshal(u.AnyOfMixedAnyOf2) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *AnyOfMixed) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 SimpleObject - if err := json.Unmarshal(data, &v1); err == nil { - u.SimpleObject = &v1 - } - - var v2 AnyOfMixedAnyOf2 - if err := json.Unmarshal(data, &v2); err == nil { - u.AnyOfMixedAnyOf2 = &v2 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AnyOfMixed) ApplyDefaults() { - if u.SimpleObject != nil { - u.SimpleObject.ApplyDefaults() - } - if u.AnyOfMixedAnyOf2 != nil { - u.AnyOfMixedAnyOf2.ApplyDefaults() - } -} - -// #/components/schemas/AnyOfMixed/anyOf/2 -type AnyOfMixedAnyOf2 struct { - Inline *bool `json:"inline,omitempty" form:"inline,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AnyOfMixedAnyOf2) ApplyDefaults() { -} - -// #/components/schemas/AnyOfNullable -type AnyOfNullable struct { - String0 *string - Any1 *any -} - -func (u AnyOfNullable) MarshalJSON() ([]byte, error) { - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.Any1 != nil { - return json.Marshal(u.Any1) - } - return []byte("null"), nil -} - -func (u *AnyOfNullable) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 any - if err := json.Unmarshal(data, &v1); err == nil { - u.Any1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AnyOfNullable) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithAnyOfProperty -type ObjectWithAnyOfProperty struct { - Value *ObjectWithAnyOfPropertyValue `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithAnyOfProperty) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithAnyOfProperty/properties/value -type ObjectWithAnyOfPropertyValue struct { - String0 *string - Int1 *int - Bool2 *bool -} - -func (u ObjectWithAnyOfPropertyValue) MarshalJSON() ([]byte, error) { - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.Int1 != nil { - return json.Marshal(u.Int1) - } - if u.Bool2 != nil { - return json.Marshal(u.Bool2) - } - return []byte("null"), nil -} - -func (u *ObjectWithAnyOfPropertyValue) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 int - if err := json.Unmarshal(data, &v1); err == nil { - u.Int1 = &v1 - } - - var v2 bool - if err := json.Unmarshal(data, &v2); err == nil { - u.Bool2 = &v2 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ObjectWithAnyOfPropertyValue) ApplyDefaults() { -} - -// #/components/schemas/ArrayOfAnyOf -type ArrayOfAnyOf = []ArrayOfAnyOfItem - -// #/components/schemas/ArrayOfAnyOf/items -type ArrayOfAnyOfItem struct { - SimpleObject *SimpleObject - BaseProperties *BaseProperties -} - -func (u ArrayOfAnyOfItem) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.SimpleObject != nil { - data, err := json.Marshal(u.SimpleObject) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.BaseProperties != nil { - data, err := json.Marshal(u.BaseProperties) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *ArrayOfAnyOfItem) UnmarshalJSON(data []byte) error { - var v0 SimpleObject - if err := json.Unmarshal(data, &v0); err == nil { - u.SimpleObject = &v0 - } - - var v1 BaseProperties - if err := json.Unmarshal(data, &v1); err == nil { - u.BaseProperties = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ArrayOfAnyOfItem) ApplyDefaults() { - if u.SimpleObject != nil { - u.SimpleObject.ApplyDefaults() - } - if u.BaseProperties != nil { - u.BaseProperties.ApplyDefaults() - } -} - -// #/components/schemas/OneOfSimple -type OneOfSimple struct { - SimpleObject *SimpleObject - BaseProperties *BaseProperties -} - -func (u OneOfSimple) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.SimpleObject != nil { - count++ - data, err = json.Marshal(u.SimpleObject) - if err != nil { - return nil, err - } - } - if u.BaseProperties != nil { - count++ - data, err = json.Marshal(u.BaseProperties) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfSimple: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfSimple) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 SimpleObject - if err := json.Unmarshal(data, &v0); err == nil { - u.SimpleObject = &v0 - successCount++ - } - - var v1 BaseProperties - if err := json.Unmarshal(data, &v1); err == nil { - u.BaseProperties = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfSimple: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfSimple) ApplyDefaults() { - if u.SimpleObject != nil { - u.SimpleObject.ApplyDefaults() - } - if u.BaseProperties != nil { - u.BaseProperties.ApplyDefaults() - } -} - -// #/components/schemas/OneOfWithDiscriminator -type OneOfWithDiscriminator struct { - Cat *Cat - Dog *Dog -} - -func (u OneOfWithDiscriminator) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.Cat != nil { - count++ - data, err = json.Marshal(u.Cat) - if err != nil { - return nil, err - } - } - if u.Dog != nil { - count++ - data, err = json.Marshal(u.Dog) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfWithDiscriminator: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfWithDiscriminator) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 Cat - if err := json.Unmarshal(data, &v0); err == nil { - u.Cat = &v0 - successCount++ - } - - var v1 Dog - if err := json.Unmarshal(data, &v1); err == nil { - u.Dog = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfWithDiscriminator: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfWithDiscriminator) ApplyDefaults() { - if u.Cat != nil { - u.Cat.ApplyDefaults() - } - if u.Dog != nil { - u.Dog.ApplyDefaults() - } -} - -// #/components/schemas/OneOfWithDiscriminatorMapping -type OneOfWithDiscriminatorMapping struct { - Cat *Cat - Dog *Dog -} - -func (u OneOfWithDiscriminatorMapping) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.Cat != nil { - count++ - data, err = json.Marshal(u.Cat) - if err != nil { - return nil, err - } - } - if u.Dog != nil { - count++ - data, err = json.Marshal(u.Dog) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfWithDiscriminatorMapping: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfWithDiscriminatorMapping) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 Cat - if err := json.Unmarshal(data, &v0); err == nil { - u.Cat = &v0 - successCount++ - } - - var v1 Dog - if err := json.Unmarshal(data, &v1); err == nil { - u.Dog = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfWithDiscriminatorMapping: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfWithDiscriminatorMapping) ApplyDefaults() { - if u.Cat != nil { - u.Cat.ApplyDefaults() - } - if u.Dog != nil { - u.Dog.ApplyDefaults() - } -} - -// #/components/schemas/Cat -type Cat struct { - PetType string `json:"petType" form:"petType"` - Meow string `json:"meow" form:"meow"` - WhiskerLength *float32 `json:"whiskerLength,omitempty" form:"whiskerLength,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Cat) ApplyDefaults() { -} - -// #/components/schemas/Dog -type Dog struct { - PetType string `json:"petType" form:"petType"` - Bark string `json:"bark" form:"bark"` - TailLength *float32 `json:"tailLength,omitempty" form:"tailLength,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Dog) ApplyDefaults() { -} - -// #/components/schemas/OneOfInline -type OneOfInline struct { - OneOfInlineOneOf0 *OneOfInlineOneOf0 - OneOfInlineOneOf1 *OneOfInlineOneOf1 -} - -func (u OneOfInline) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.OneOfInlineOneOf0 != nil { - count++ - data, err = json.Marshal(u.OneOfInlineOneOf0) - if err != nil { - return nil, err - } - } - if u.OneOfInlineOneOf1 != nil { - count++ - data, err = json.Marshal(u.OneOfInlineOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfInline: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfInline) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 OneOfInlineOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.OneOfInlineOneOf0 = &v0 - successCount++ - } - - var v1 OneOfInlineOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.OneOfInlineOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfInline: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfInline) ApplyDefaults() { - if u.OneOfInlineOneOf0 != nil { - u.OneOfInlineOneOf0.ApplyDefaults() - } - if u.OneOfInlineOneOf1 != nil { - u.OneOfInlineOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/OneOfInline/oneOf/0 -type OneOfInlineOneOf0 struct { - OptionA *string `json:"optionA,omitempty" form:"optionA,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfInlineOneOf0) ApplyDefaults() { -} - -// #/components/schemas/OneOfInline/oneOf/1 -type OneOfInlineOneOf1 struct { - OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfInlineOneOf1) ApplyDefaults() { -} - -// #/components/schemas/OneOfPrimitives -type OneOfPrimitives struct { - String0 *string - Float321 *float32 - Bool2 *bool -} - -func (u OneOfPrimitives) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.String0 != nil { - count++ - data, err = json.Marshal(u.String0) - if err != nil { - return nil, err - } - } - if u.Float321 != nil { - count++ - data, err = json.Marshal(u.Float321) - if err != nil { - return nil, err - } - } - if u.Bool2 != nil { - count++ - data, err = json.Marshal(u.Bool2) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfPrimitives: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfPrimitives) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - successCount++ - } - - var v1 float32 - if err := json.Unmarshal(data, &v1); err == nil { - u.Float321 = &v1 - successCount++ - } - - var v2 bool - if err := json.Unmarshal(data, &v2); err == nil { - u.Bool2 = &v2 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfPrimitives: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfPrimitives) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithOneOfProperty -type ObjectWithOneOfProperty struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - Variant *ObjectWithOneOfPropertyVariant `json:"variant,omitempty" form:"variant,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithOneOfProperty) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithOneOfProperty/properties/variant -type ObjectWithOneOfPropertyVariant struct { - Cat *Cat - Dog *Dog -} - -func (u ObjectWithOneOfPropertyVariant) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.Cat != nil { - count++ - data, err = json.Marshal(u.Cat) - if err != nil { - return nil, err - } - } - if u.Dog != nil { - count++ - data, err = json.Marshal(u.Dog) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("ObjectWithOneOfPropertyVariant: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *ObjectWithOneOfPropertyVariant) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 Cat - if err := json.Unmarshal(data, &v0); err == nil { - u.Cat = &v0 - successCount++ - } - - var v1 Dog - if err := json.Unmarshal(data, &v1); err == nil { - u.Dog = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("ObjectWithOneOfPropertyVariant: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ObjectWithOneOfPropertyVariant) ApplyDefaults() { - if u.Cat != nil { - u.Cat.ApplyDefaults() - } - if u.Dog != nil { - u.Dog.ApplyDefaults() - } -} - -// #/components/schemas/AllOfWithOneOf -type AllOfWithOneOf struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - AllOfWithOneOfAllOf1 *AllOfWithOneOfAllOf1 `json:"-"` -} - -func (s AllOfWithOneOf) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if s.ID != nil { - result["id"] = s.ID - } - if s.CreatedAt != nil { - result["createdAt"] = s.CreatedAt - } - - if s.AllOfWithOneOfAllOf1 != nil { - unionData, err := json.Marshal(s.AllOfWithOneOfAllOf1) - if err != nil { - return nil, err - } - var unionMap map[string]any - if err := json.Unmarshal(unionData, &unionMap); err == nil { - for k, v := range unionMap { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (s *AllOfWithOneOf) UnmarshalJSON(data []byte) error { - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["id"]; ok { - var val int - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.ID = &val - } - if v, ok := raw["createdAt"]; ok { - var val time.Time - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.CreatedAt = &val - } - - var AllOfWithOneOfAllOf1Val AllOfWithOneOfAllOf1 - if err := json.Unmarshal(data, &AllOfWithOneOfAllOf1Val); err != nil { - return err - } - s.AllOfWithOneOfAllOf1 = &AllOfWithOneOfAllOf1Val - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithOneOf) ApplyDefaults() { -} - -// #/components/schemas/AllOfWithOneOf/allOf/1 -type AllOfWithOneOfAllOf1 struct { - Cat *Cat - Dog *Dog -} - -func (u AllOfWithOneOfAllOf1) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.Cat != nil { - count++ - data, err = json.Marshal(u.Cat) - if err != nil { - return nil, err - } - } - if u.Dog != nil { - count++ - data, err = json.Marshal(u.Dog) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("AllOfWithOneOfAllOf1: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *AllOfWithOneOfAllOf1) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 Cat - if err := json.Unmarshal(data, &v0); err == nil { - u.Cat = &v0 - successCount++ - } - - var v1 Dog - if err := json.Unmarshal(data, &v1); err == nil { - u.Dog = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("AllOfWithOneOfAllOf1: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AllOfWithOneOfAllOf1) ApplyDefaults() { - if u.Cat != nil { - u.Cat.ApplyDefaults() - } - if u.Dog != nil { - u.Dog.ApplyDefaults() - } -} - -// #/components/schemas/OneOfWithAllOf -type OneOfWithAllOf struct { - OneOfWithAllOfOneOf0 *OneOfWithAllOfOneOf0 - OneOfWithAllOfOneOf1 *OneOfWithAllOfOneOf1 -} - -func (u OneOfWithAllOf) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.OneOfWithAllOfOneOf0 != nil { - count++ - data, err = json.Marshal(u.OneOfWithAllOfOneOf0) - if err != nil { - return nil, err - } - } - if u.OneOfWithAllOfOneOf1 != nil { - count++ - data, err = json.Marshal(u.OneOfWithAllOfOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfWithAllOf: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfWithAllOf) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 OneOfWithAllOfOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.OneOfWithAllOfOneOf0 = &v0 - successCount++ - } - - var v1 OneOfWithAllOfOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.OneOfWithAllOfOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfWithAllOf: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfWithAllOf) ApplyDefaults() { - if u.OneOfWithAllOfOneOf0 != nil { - u.OneOfWithAllOfOneOf0.ApplyDefaults() - } - if u.OneOfWithAllOfOneOf1 != nil { - u.OneOfWithAllOfOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/OneOfWithAllOf/oneOf/0 -type OneOfWithAllOfOneOf0 struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Variant *string `json:"variant,omitempty" form:"variant,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfWithAllOfOneOf0) ApplyDefaults() { -} - -// #/components/schemas/OneOfWithAllOf/oneOf/1 -type OneOfWithAllOfOneOf1 struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Variant *string `json:"variant,omitempty" form:"variant,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfWithAllOfOneOf1) ApplyDefaults() { -} - -// #/components/schemas/TreeNode -type TreeNode struct { - Value *string `json:"value,omitempty" form:"value,omitempty"` - Children []TreeNode `json:"children,omitempty" form:"children,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TreeNode) ApplyDefaults() { -} - -// #/components/schemas/TreeNode/properties/children -type TreeNodeChildren = []TreeNode - -// #/components/schemas/LinkedListNode -type LinkedListNode struct { - Value *int `json:"value,omitempty" form:"value,omitempty"` - Next *LinkedListNode `json:"next,omitempty" form:"next,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *LinkedListNode) ApplyDefaults() { - if s.Next != nil { - s.Next.ApplyDefaults() - } -} - -// #/components/schemas/RecursiveOneOf -type RecursiveOneOf struct { - String0 *string - RecursiveOneOfOneOf1 *RecursiveOneOfOneOf1 -} - -func (u RecursiveOneOf) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.String0 != nil { - count++ - data, err = json.Marshal(u.String0) - if err != nil { - return nil, err - } - } - if u.RecursiveOneOfOneOf1 != nil { - count++ - data, err = json.Marshal(u.RecursiveOneOfOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("RecursiveOneOf: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *RecursiveOneOf) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - successCount++ - } - - var v1 RecursiveOneOfOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.RecursiveOneOfOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("RecursiveOneOf: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *RecursiveOneOf) ApplyDefaults() { - if u.RecursiveOneOfOneOf1 != nil { - u.RecursiveOneOfOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/RecursiveOneOf/oneOf/1 -type RecursiveOneOfOneOf1 struct { - Nested *RecursiveOneOf `json:"nested,omitempty" form:"nested,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *RecursiveOneOfOneOf1) ApplyDefaults() { - if s.Nested != nil { - s.Nested.ApplyDefaults() - } -} - -// #/components/schemas/ReadWriteOnly -type ReadWriteOnly struct { - ID int `json:"id" form:"id"` - Password string `json:"password" form:"password"` - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ReadWriteOnly) ApplyDefaults() { -} - -// #/components/schemas/WithDefaults -type WithDefaults struct { - StringWithDefault *string `json:"stringWithDefault,omitempty" form:"stringWithDefault,omitempty"` - IntWithDefault *int `json:"intWithDefault,omitempty" form:"intWithDefault,omitempty"` - BoolWithDefault *bool `json:"boolWithDefault,omitempty" form:"boolWithDefault,omitempty"` - ArrayWithDefault []string `json:"arrayWithDefault,omitempty" form:"arrayWithDefault,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *WithDefaults) ApplyDefaults() { - if s.StringWithDefault == nil { - v := "default_value" - s.StringWithDefault = &v - } - if s.IntWithDefault == nil { - v := 42 - s.IntWithDefault = &v - } - if s.BoolWithDefault == nil { - v := true - s.BoolWithDefault = &v - } -} - -// #/components/schemas/WithConst -type WithConst struct { - Version *string `json:"version,omitempty" form:"version,omitempty"` - Type *string `json:"type,omitempty" form:"type,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *WithConst) ApplyDefaults() { -} - -// #/components/schemas/WithConstraints -type WithConstraints struct { - BoundedInt *int `json:"boundedInt,omitempty" form:"boundedInt,omitempty"` - ExclusiveBoundedInt *int `json:"exclusiveBoundedInt,omitempty" form:"exclusiveBoundedInt,omitempty"` - MultipleOf *int `json:"multipleOf,omitempty" form:"multipleOf,omitempty"` - BoundedString *string `json:"boundedString,omitempty" form:"boundedString,omitempty"` - PatternString *string `json:"patternString,omitempty" form:"patternString,omitempty"` - BoundedArray []string `json:"boundedArray,omitempty" form:"boundedArray,omitempty"` - UniqueArray []string `json:"uniqueArray,omitempty" form:"uniqueArray,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *WithConstraints) ApplyDefaults() { -} - -// #/components/schemas/TypeArray31 -type TypeArray31 struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TypeArray31) ApplyDefaults() { -} - -// #/components/schemas/ExplicitAny -type ExplicitAny = Nullable[string] - -// #/components/schemas/ComplexNested -type ComplexNested struct { - Metadata map[string]any `json:"metadata,omitempty" form:"metadata,omitempty"` - Items []ComplexNestedItemItem `json:"items,omitempty" form:"items,omitempty"` - Config *ComplexNestedConfig `json:"config,omitempty" form:"config,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexNested) ApplyDefaults() { -} - -// #/components/schemas/ComplexNested/properties/metadata -type ComplexNestedMetadata = map[string]any - -// #/components/schemas/ComplexNested/properties/metadata/additionalProperties -type ComplexNestedMetadataValue struct { - String0 *string - Int1 *int - LBracketString2 *[]string -} - -func (u ComplexNestedMetadataValue) MarshalJSON() ([]byte, error) { - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.Int1 != nil { - return json.Marshal(u.Int1) - } - if u.LBracketString2 != nil { - return json.Marshal(u.LBracketString2) - } - return []byte("null"), nil -} - -func (u *ComplexNestedMetadataValue) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 int - if err := json.Unmarshal(data, &v1); err == nil { - u.Int1 = &v1 - } - - var v2 []string - if err := json.Unmarshal(data, &v2); err == nil { - u.LBracketString2 = &v2 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ComplexNestedMetadataValue) ApplyDefaults() { -} - -// #/components/schemas/ComplexNested/properties/items -type ComplexNestedItem = []ComplexNestedItemItem - -// #/components/schemas/ComplexNested/properties/items/items -type ComplexNestedItemItem struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty" form:"createdAt,omitempty"` - Tags []string `json:"tags,omitempty" form:"tags,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexNestedItemItem) ApplyDefaults() { -} - -// #/components/schemas/ComplexNested/properties/config -type ComplexNestedConfig struct { - ComplexNestedConfigOneOf0 *ComplexNestedConfigOneOf0 - ComplexNestedConfigOneOf1 *ComplexNestedConfigOneOf1 -} - -func (u ComplexNestedConfig) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.ComplexNestedConfigOneOf0 != nil { - count++ - data, err = json.Marshal(u.ComplexNestedConfigOneOf0) - if err != nil { - return nil, err - } - } - if u.ComplexNestedConfigOneOf1 != nil { - count++ - data, err = json.Marshal(u.ComplexNestedConfigOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("ComplexNestedConfig: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *ComplexNestedConfig) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 ComplexNestedConfigOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.ComplexNestedConfigOneOf0 = &v0 - successCount++ - } - - var v1 ComplexNestedConfigOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.ComplexNestedConfigOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("ComplexNestedConfig: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ComplexNestedConfig) ApplyDefaults() { - if u.ComplexNestedConfigOneOf0 != nil { - u.ComplexNestedConfigOneOf0.ApplyDefaults() - } - if u.ComplexNestedConfigOneOf1 != nil { - u.ComplexNestedConfigOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/ComplexNested/properties/config/oneOf/0 -type ComplexNestedConfigOneOf0 struct { - Mode *string `json:"mode,omitempty" form:"mode,omitempty"` - Value *string `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexNestedConfigOneOf0) ApplyDefaults() { -} - -// #/components/schemas/ComplexNested/properties/config/oneOf/1 -type ComplexNestedConfigOneOf1 struct { - Mode *string `json:"mode,omitempty" form:"mode,omitempty"` - Options map[string]string `json:"options,omitempty" form:"options,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexNestedConfigOneOf1) ApplyDefaults() { -} - -// #/components/schemas/ComplexNested/properties/config/oneOf/1/properties/options -type ComplexNestedConfigOneOf1Options = map[string]string - -// #/components/schemas/StringMap -type StringMap = map[string]string - -// #/components/schemas/ObjectMap -type ObjectMap = map[string]any - -// #/components/schemas/NestedMap -type NestedMap = map[string]map[string]string - -// #/components/schemas/NestedMap/additionalProperties -type NestedMapValue = map[string]string - -// #/paths//inline-response/get/responses/200/content/application/json/schema -type GetInlineResponseJSONResponse struct { - ID int `json:"id" form:"id"` - Name string `json:"name" form:"name"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *GetInlineResponseJSONResponse) ApplyDefaults() { -} - -const DateFormat = "2006-01-02" - -type Date struct { - time.Time -} - -func (d Date) MarshalJSON() ([]byte, error) { - return json.Marshal(d.Format(DateFormat)) -} - -func (d *Date) UnmarshalJSON(data []byte) error { - var dateStr string - err := json.Unmarshal(data, &dateStr) - if err != nil { - return err - } - parsed, err := time.Parse(DateFormat, dateStr) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -func (d Date) String() string { - return d.Format(DateFormat) -} - -func (d *Date) UnmarshalText(data []byte) error { - parsed, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -const ( - emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" -) - -var ( - emailRegex = regexp.MustCompile(emailRegexString) -) - -// ErrValidationEmail is the sentinel error returned when an email fails validation -var ErrValidationEmail = errors.New("email: failed to pass regex validation") - -// Email represents an email address. -// It is a string type that must pass regex validation before being marshalled -// to JSON or unmarshalled from JSON. -type Email string - -func (e Email) MarshalJSON() ([]byte, error) { - if !emailRegex.MatchString(string(e)) { - return nil, ErrValidationEmail - } - - return json.Marshal(string(e)) -} - -func (e *Email) UnmarshalJSON(data []byte) error { - if e == nil { - return nil - } - - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - - *e = Email(s) - if !emailRegex.MatchString(s) { - return ErrValidationEmail - } - - return nil -} - -type File struct { - multipart *multipart.FileHeader - data []byte - filename string -} - -func (file *File) InitFromMultipart(header *multipart.FileHeader) { - file.multipart = header - file.data = nil - file.filename = "" -} - -func (file *File) InitFromBytes(data []byte, filename string) { - file.data = data - file.filename = filename - file.multipart = nil -} - -func (file File) MarshalJSON() ([]byte, error) { - b, err := file.Bytes() - if err != nil { - return nil, err - } - return json.Marshal(b) -} - -func (file *File) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &file.data) -} - -func (file File) Bytes() ([]byte, error) { - if file.multipart != nil { - f, err := file.multipart.Open() - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return io.ReadAll(f) - } - return file.data, nil -} - -func (file File) Reader() (io.ReadCloser, error) { - if file.multipart != nil { - return file.multipart.Open() - } - return io.NopCloser(bytes.NewReader(file.data)), nil -} - -func (file File) Filename() string { - if file.multipart != nil { - return file.multipart.Filename - } - return file.filename -} - -func (file File) FileSize() int64 { - if file.multipart != nil { - return file.multipart.Size - } - return int64(len(file.data)) -} - -// Nullable is a generic type that can distinguish between: -// - Field not provided (unspecified) -// - Field explicitly set to null -// - Field has a value -// -// This is implemented as a map[bool]T where: -// - Empty map: unspecified -// - map[false]T: explicitly null -// - map[true]T: has a value -type Nullable[T any] map[bool]T - -// NewNullableWithValue creates a Nullable with the given value. -func NewNullableWithValue[T any](value T) Nullable[T] { - return Nullable[T]{true: value} -} - -// NewNullNullable creates a Nullable that is explicitly null. -func NewNullNullable[T any]() Nullable[T] { - return Nullable[T]{false: *new(T)} -} - -// Get returns the value if set, or an error if null or unspecified. -func (n Nullable[T]) Get() (T, error) { - if v, ok := n[true]; ok { - return v, nil - } - var zero T - if n.IsNull() { - return zero, ErrNullableIsNull - } - return zero, ErrNullableNotSpecified -} - -// MustGet returns the value or panics if null or unspecified. -func (n Nullable[T]) MustGet() T { - v, err := n.Get() - if err != nil { - panic(err) - } - return v -} - -// Set assigns a value. -func (n *Nullable[T]) Set(value T) { - *n = Nullable[T]{true: value} -} - -// SetNull marks the field as explicitly null. -func (n *Nullable[T]) SetNull() { - *n = Nullable[T]{false: *new(T)} -} - -// SetUnspecified clears the field (as if it was never set). -func (n *Nullable[T]) SetUnspecified() { - *n = nil -} - -// IsNull returns true if the field is explicitly null. -func (n Nullable[T]) IsNull() bool { - if n == nil { - return false - } - _, ok := n[false] - return ok -} - -// IsSpecified returns true if the field was provided (either null or a value). -func (n Nullable[T]) IsSpecified() bool { - return len(n) > 0 -} - -// MarshalJSON implements json.Marshaler. -func (n Nullable[T]) MarshalJSON() ([]byte, error) { - if n.IsNull() { - return []byte("null"), nil - } - if v, ok := n[true]; ok { - return json.Marshal(v) - } - // Unspecified - this shouldn't be called if omitempty is used correctly - return []byte("null"), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (n *Nullable[T]) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - n.SetNull() - return nil - } - var v T - if err := json.Unmarshal(data, &v); err != nil { - return err - } - n.Set(v) - return nil -} - -// ErrNullableIsNull is returned when trying to get a value from a null Nullable. -var ErrNullableIsNull = errors.New("nullable value is null") - -// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. -var ErrNullableNotSpecified = errors.New("nullable value is not specified") - -type UUID = uuid.UUID - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/+wcXW8iOfKdX2Gx+3Zi8jGz84B0D4QwEnsEEJCdi1Z7J4cuEu90u3vcJgm32v9+st10", - "tz/6y2RGs6PNEynb9eVyVblcECdAcUKGqP/2zcWb836P0F087CHECQ9hiMZxlDB4BJqSJ0AbSDlabx8h", - "wj2EnoClJKZD1L94cy7WIhRAumUk4RIsZqcIhyFK5RKUYM6B0RTtYoZinJDBNg7gAWivl2D+mAq6ZymJ", - "khDER4QegKsPCMUJMCzwToOhgK/ltGyQQZrENIX0OBuh/uX5eb/412BNrc7XlaZtY8qB8vJKhHCShGQr", - "yZ/9nsZUH0WZfCYUoR8Z7Iao/8PZNo6SmALl6Zmam54pFhb3v8OW93tCckJDQmFwZKpRBVM5f6XL0FkV", - "CguKJSOI0C+uFH5IYJjRswYZfN4TBoG9DKEBIoETTHEE1kDChL44KWui+CNOCkfmCOXwAMwxQ5CqW5ly", - "RuiD3M4EMxwBB5ae/SHMeyn+/1MtLsaOyJQUQ5TPzIkQqqA9S0eIs30huK1vjaUCvItZhPkQ7feZPmts", - "7CPJ2JHMZpNs7gv+P++BHdYmSSGDHOnV24eTYw31lHJvvOa2aohHjOGDN2psrEaIcIgs06uV7xFwAEzf", - "fMWHGumuu87OYPGvb8MVChOHlA/u4+CQnZg4dRupGFip6VdxcOgVZySDDJsOjkPOeindMtZJOArDzSGB", - "dJVx0P+rb1C0D7kI3yUGanfoRswfq+l1W/QV9kIXxk3nZfD8/DwQjnKwZyFQkacEX4qw1GWCGT+TBAPM", - "cRtSNXG0LvbtSOiMYBXBwgwa94RidrAmRMCxzfj35Zg0meCFnyUhJh3TnmN+UBATMzN6atEP6J/t/7IV", - "y9X0ZrqZ/jJBm7vlZI0GaBSG2Z6lHljlEtNpHWVyGJ6dtg1EtP1AIAx00NtLB/D9OxO4C2NsLQ/i/X0I", - "JpTuo3tgJlQp2oTex3FoYcUcXLANiSy4SJlMGESYWEj3jJigxzjlItBb8idP7xyw9xbvB5tPdRpNaILT", - "9DlmGqcul3DcITtnNDOlYuOa5xa+Qq4q48j2uSOO9+9yeGEWNg5lBw4UclEOLxlRBxxqVT5QsrlGJCVL", - "bEzOc/u0Z4ohwLSQ42i2HTJ+sUZDkNt4RyQDTkpXrvxU+Fw+xF9xhDpgkIsKHrID14UFRnKodjg74Diu", - "K6z8eJo7IBFrygjeeyB4X9jQobthiDUFgsKpdEGhJwaaD+qA5rhOD0ELmQbgsCYE/e3g/nZw36OD884J", - "57ez2ehqlqWEvkngfB+G+D4EzySQZsvXVskjGyjXcwrooulk63gtpfb0AqHjVjNAfYGjb2Gc6hcLFzpX", - "ebASnxKlCaXjGmdhrL7XuaqSZj2y2EpPZ/rtqtz7iIxWq9Gd99GQFUMZnjpqUulGLrfdgVlJdNQRnX6D", - "UH4qRlPJShB/rN2v1uoJZHEi3crKSHVdxPUeUPcW4H4HcG4MhZRDcKo0pxSYj+fMzYNxpmxCDkfU1igl", - "so+EP45jmnKGSVbwqJctInQqCaCLMhS/HKHnHVjxdg6Lq58n4423dygbeNfKSe2lvUV2aVqnIxZIo2zk", - "zsVAvOfAbOzWcas6bIRSff0JxcwnHO6bq5n+8eH6erqZLuajGVquFsvJajP1z6RGQUBU4F2yOElH9FCj", - "eKxNzsRXzxYuZPOYQmdsOxzmr7wuJX+i8TOtNyODDREMg6589Ny27MLfaK/1BDo9cVjE5VOo+ND1Etp4", - "YNuo5VRTnsxvb/x9mSQ+oftIl13z9lAaFl5Mns0LE3BpAt4qElOlEZuGriqTSBl/GXWGVe2n2DkbcYs0", - "DfN92uLCpjOV1WCBBnYCjLecPIEBFNYYAofiupgwEjPCD23qCC7iF8b/l8b/uc5FtiU0M6WZ5R06V1gE", - "ivUpmoqpCdjtTnDZs9niAxqgKX0ERjimWzgbi+OeyiPmewKucAr24Xw1D4DQlgEWaSL3KlTIwckLBxqY", - "UR2H4WJXPjJ1XlAXs19aVRGg3f06VkuO98W1PFB+EGy87F4DJCUb8NKGrtAW2qgSE144w808jwRz8qU8", - "CWEFu/SV97D7fayzpBGwB7t7Sy/wFbIqB7Sg4aFS0o70d4SlvGXXTUfUKWxjWiGalrR4ua35nXRbt5TE", - "FMmigneeSQ+L3ZKRiIhYU9iQANuardCKnoWJpco0qtH5GFcXMy44uSEvhYm1Fesr2L6KhW1sX/B8rMb5", - "7U+58lUkOdnWe0Vy6yplMFTDlMtwXGO6EsSlf7EblanY5QDjdm/xNPDq3/CwPK8KwnwiD/U1EYErIlRE", - "eHXEvU/3gsJity71SCMUC9BXP4qSEWF0Jeli5sXTGLdm5Tp+OE4NXHRz2z7MVTstcOFM61i+wUlSKmh/", - "a5wX5S+NTZkziiSwBWMIBfFDLV9y6hh3LVSZPA5QBPFzjZPJFjTmuAJN46TnR5J+AjYD+sAfK18pVTYY", - "P5ws2j1mn15BNIGmcRLHJGwjl7ToqRZ3LPvtGMVimWCPvkwOpZBftUiipGR2FlMhXQVfxkO1Mw4V0TMj", - "6XcPbnHFe8KMYP2pyxCno8Pp5HRqHE+D2/QJfePFzdV0PrkWH5aLtayintCHqNz2oqytV7oT/SV2IA9c", - "o7LQ1lkwVOKvltqz3VyTt8y8ZY/xNqapiGi4/x0KdX9CIrmajG9X67y91/cgbRjAPA7g1JuBU+LtIwkD", - "BvTVX4qPXGf6mxH6CYIZSfnriWK9n8GLttV17On8ZEyuYLtnKXkCzWV1C16tg6p6YO7yTQSdvZMMc3R9", - "9nE13UzQYj678zXMFeDgIyNcKwV1fSwtdz6fGKkFJRxIZvSvCh3xtyjSPufy6Cia32Z9NuJ68mF0O9us", - "0WguYu58vfHdC3k/gh3eh9yvr6WEoIWagmwm6mef/ivPaLklhNditPcuR/nuUus7rEVjdh+W0Gjbl3c0", - "VGLybeApUfz1t2IvZOdEVzeXfTO7Wf3H6JR/g9vdGNKwekdeIOifki3O15vVaDr3b7eoaDJpqbD7eE8D", - "CFyNaA4Diwgl0T4aonO9PUUBL84LMLxsw71wtFedCOTLblyUilEXySh7P9CTpkpRitnoJ1MdFZ1+th1E", - "hGa3VbNj5wi+/OmnkhOVPwPQGns2f4j6//kVD/732z9+7JuctuyuetXGorw5mJLPe2jJgZqckdMcy5fs", - "ZFpO5qPlFL19c4HWy8l4+mE69s4hD4mS9e2FdsZ6lb2sRvuYs7W0MSYuGeyI2iaDsKbipJjW+amjqkrg", - "3JxXasq4WW7u0Bkaze9kZu+7KZMo4Qf1uxxD9Mef+SvDL+V0V/s+5Wi7hYSnCNMD+nm9mKvM+PiOnIRk", - "S7jZodSr7O4d2JUWW6tmhDVbDasN55QqxHI2+TeaT9abyTVab1a3483tyv8GNZatGi9zLeNuGWNcX5Gt", - "yPTrG4IqHmdqn2fqH2iKUbv7s7LVtLoT2ZzdOi9y3PVPue033PebfiOE44e07rc+3Lqq1Vf17TmmO/LQ", - "WBr0rF5EpZuyR+lC/SRP37P78luQAAdPmG6L310wK9I1xl1hOm0O6esGi5vR8sQGvhucnNicWZZBFc5P", - "wdmxH1N53dOFMHa0aR81yf8fAAD//ynhbdUwSwAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/default_values/default_values.yaml b/experimental/internal/codegen/test/default_values/default_values.yaml deleted file mode 100644 index 8f773e63ee..0000000000 --- a/experimental/internal/codegen/test/default_values/default_values.yaml +++ /dev/null @@ -1,158 +0,0 @@ -openapi: "3.1.0" -info: - title: Default Values Test - version: "1.0" -paths: {} -components: - schemas: - # Basic primitives with defaults - SimpleDefaults: - type: object - properties: - stringField: - type: string - default: "hello" - intField: - type: integer - default: 42 - boolField: - type: boolean - default: true - floatField: - type: number - default: 3.14 - int64Field: - type: integer - format: int64 - default: 9223372036854775807 - - # Nested objects - should recurse ApplyDefaults - NestedDefaults: - type: object - properties: - name: - type: string - default: "parent" - child: - $ref: '#/components/schemas/SimpleDefaults' - inlineChild: - type: object - properties: - label: - type: string - default: "inline-default" - value: - type: integer - default: 100 - - # Object with additionalProperties and defaults - MapWithDefaults: - type: object - properties: - prefix: - type: string - default: "map-" - additionalProperties: - type: string - - # Array field with defaults - ArrayDefaults: - type: object - properties: - items: - type: array - items: - type: string - default: [] - count: - type: integer - default: 0 - - # anyOf with defaults in members - AnyOfWithDefaults: - type: object - properties: - value: - anyOf: - - type: object - properties: - stringVal: - type: string - default: "default-string" - - type: object - properties: - intVal: - type: integer - default: 999 - - # oneOf with defaults in members - OneOfWithDefaults: - type: object - properties: - variant: - oneOf: - - type: object - properties: - optionA: - type: string - default: "option-a-default" - - type: object - properties: - optionB: - type: integer - default: 123 - - # allOf with defaults - AllOfWithDefaults: - allOf: - - type: object - properties: - base: - type: string - default: "base-value" - - type: object - properties: - extended: - type: integer - default: 50 - - # Deep nesting - multiple levels - DeepNesting: - type: object - properties: - level1: - type: object - properties: - name: - type: string - default: "level1-name" - level2: - type: object - properties: - count: - type: integer - default: 2 - level3: - type: object - properties: - enabled: - type: boolean - default: false - - # Required vs optional with defaults - RequiredAndOptional: - type: object - required: - - requiredWithDefault - - requiredNoDefault - properties: - requiredWithDefault: - type: string - default: "required-default" - requiredNoDefault: - type: string - optionalWithDefault: - type: string - default: "optional-default" - optionalNoDefault: - type: string diff --git a/experimental/internal/codegen/test/default_values/output/default_values.gen.go b/experimental/internal/codegen/test/default_values/output/default_values.gen.go deleted file mode 100644 index a8b988994d..0000000000 --- a/experimental/internal/codegen/test/default_values/output/default_values.gen.go +++ /dev/null @@ -1,514 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "encoding/json" - "fmt" -) - -// #/components/schemas/SimpleDefaults -type SimpleDefaultsSchemaComponent struct { - StringField *string `json:"stringField,omitempty" form:"stringField,omitempty"` - IntField *int `json:"intField,omitempty" form:"intField,omitempty"` - BoolField *bool `json:"boolField,omitempty" form:"boolField,omitempty"` - FloatField *float32 `json:"floatField,omitempty" form:"floatField,omitempty"` - Int64Field *int64 `json:"int64Field,omitempty" form:"int64Field,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *SimpleDefaultsSchemaComponent) ApplyDefaults() { - if s.StringField == nil { - v := "hello" - s.StringField = &v - } - if s.IntField == nil { - v := 42 - s.IntField = &v - } - if s.BoolField == nil { - v := true - s.BoolField = &v - } - if s.FloatField == nil { - v := float32(3.14) - s.FloatField = &v - } - if s.Int64Field == nil { - v := int64(9223372036854775807) - s.Int64Field = &v - } -} - -type SimpleDefaults = SimpleDefaultsSchemaComponent - -// #/components/schemas/NestedDefaults -type NestedDefaultsSchemaComponent struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` - Child *SimpleDefaults `json:"child,omitempty" form:"child,omitempty"` - InlineChild *NestedDefaultsInlineChild `json:"inlineChild,omitempty" form:"inlineChild,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NestedDefaultsSchemaComponent) ApplyDefaults() { - if s.Name == nil { - v := "parent" - s.Name = &v - } - if s.Child != nil { - s.Child.ApplyDefaults() - } - if s.InlineChild != nil { - s.InlineChild.ApplyDefaults() - } -} - -type NestedDefaults = NestedDefaultsSchemaComponent - -// #/components/schemas/NestedDefaults/properties/inlineChild -type NestedDefaultsInlineChildPropertySchemaComponent struct { - Label *string `json:"label,omitempty" form:"label,omitempty"` - Value *int `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *NestedDefaultsInlineChildPropertySchemaComponent) ApplyDefaults() { - if s.Label == nil { - v := "inline-default" - s.Label = &v - } - if s.Value == nil { - v := 100 - s.Value = &v - } -} - -type NestedDefaultsInlineChild = NestedDefaultsInlineChildPropertySchemaComponent - -// #/components/schemas/MapWithDefaults -type MapWithDefaultsSchemaComponent struct { - Prefix *string `json:"prefix,omitempty" form:"prefix,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -func (s MapWithDefaultsSchemaComponent) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if s.Prefix != nil { - result["prefix"] = s.Prefix - } - - // Add additional properties - for k, v := range s.AdditionalProperties { - result[k] = v - } - - return json.Marshal(result) -} - -func (s *MapWithDefaultsSchemaComponent) UnmarshalJSON(data []byte) error { - // Known fields - knownFields := map[string]bool{ - "prefix": true, - } - - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["prefix"]; ok { - var val string - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.Prefix = &val - } - - // Collect additional properties - s.AdditionalProperties = make(map[string]string) - for k, v := range raw { - if !knownFields[k] { - var val string - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.AdditionalProperties[k] = val - } - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *MapWithDefaultsSchemaComponent) ApplyDefaults() { - if s.Prefix == nil { - v := "map-" - s.Prefix = &v - } -} - -type MapWithDefaults = MapWithDefaultsSchemaComponent - -// #/components/schemas/ArrayDefaults -type ArrayDefaultsSchemaComponent struct { - Items []string `json:"items,omitempty" form:"items,omitempty"` - Count *int `json:"count,omitempty" form:"count,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ArrayDefaultsSchemaComponent) ApplyDefaults() { - if s.Count == nil { - v := 0 - s.Count = &v - } -} - -type ArrayDefaults = ArrayDefaultsSchemaComponent - -// #/components/schemas/AnyOfWithDefaults -type AnyOfWithDefaultsSchemaComponent struct { - Value *AnyOfWithDefaultsValue `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AnyOfWithDefaultsSchemaComponent) ApplyDefaults() { -} - -type AnyOfWithDefaults = AnyOfWithDefaultsSchemaComponent - -// #/components/schemas/AnyOfWithDefaults/properties/value -type AnyOfWithDefaultsValuePropertySchemaComponent struct { - AnyOfWithDefaultsValueAnyOf0 *AnyOfWithDefaultsValueAnyOf0 - AnyOfWithDefaultsValueAnyOf1 *AnyOfWithDefaultsValueAnyOf1 -} - -func (u AnyOfWithDefaultsValuePropertySchemaComponent) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.AnyOfWithDefaultsValueAnyOf0 != nil { - data, err := json.Marshal(u.AnyOfWithDefaultsValueAnyOf0) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.AnyOfWithDefaultsValueAnyOf1 != nil { - data, err := json.Marshal(u.AnyOfWithDefaultsValueAnyOf1) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *AnyOfWithDefaultsValuePropertySchemaComponent) UnmarshalJSON(data []byte) error { - var v0 AnyOfWithDefaultsValueAnyOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.AnyOfWithDefaultsValueAnyOf0 = &v0 - } - - var v1 AnyOfWithDefaultsValueAnyOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.AnyOfWithDefaultsValueAnyOf1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AnyOfWithDefaultsValuePropertySchemaComponent) ApplyDefaults() { - if u.AnyOfWithDefaultsValueAnyOf0 != nil { - u.AnyOfWithDefaultsValueAnyOf0.ApplyDefaults() - } - if u.AnyOfWithDefaultsValueAnyOf1 != nil { - u.AnyOfWithDefaultsValueAnyOf1.ApplyDefaults() - } -} - -type AnyOfWithDefaultsValue = AnyOfWithDefaultsValuePropertySchemaComponent - -// #/components/schemas/AnyOfWithDefaults/properties/value/anyOf/0 -type AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent struct { - StringVal *string `json:"stringVal,omitempty" form:"stringVal,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent) ApplyDefaults() { - if s.StringVal == nil { - v := "default-string" - s.StringVal = &v - } -} - -type AnyOfWithDefaultsValueAnyOf0 = AnyOfWithDefaultsValueN0AnyOfPropertySchemaComponent - -// #/components/schemas/AnyOfWithDefaults/properties/value/anyOf/1 -type AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent struct { - IntVal *int `json:"intVal,omitempty" form:"intVal,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent) ApplyDefaults() { - if s.IntVal == nil { - v := 999 - s.IntVal = &v - } -} - -type AnyOfWithDefaultsValueAnyOf1 = AnyOfWithDefaultsValueN1AnyOfPropertySchemaComponent - -// #/components/schemas/OneOfWithDefaults -type OneOfWithDefaultsSchemaComponent struct { - Variant *OneOfWithDefaultsVariant `json:"variant,omitempty" form:"variant,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfWithDefaultsSchemaComponent) ApplyDefaults() { -} - -type OneOfWithDefaults = OneOfWithDefaultsSchemaComponent - -// #/components/schemas/OneOfWithDefaults/properties/variant -type OneOfWithDefaultsVariantPropertySchemaComponent struct { - OneOfWithDefaultsVariantOneOf0 *OneOfWithDefaultsVariantOneOf0 - OneOfWithDefaultsVariantOneOf1 *OneOfWithDefaultsVariantOneOf1 -} - -func (u OneOfWithDefaultsVariantPropertySchemaComponent) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.OneOfWithDefaultsVariantOneOf0 != nil { - count++ - data, err = json.Marshal(u.OneOfWithDefaultsVariantOneOf0) - if err != nil { - return nil, err - } - } - if u.OneOfWithDefaultsVariantOneOf1 != nil { - count++ - data, err = json.Marshal(u.OneOfWithDefaultsVariantOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("OneOfWithDefaultsVariantPropertySchemaComponent: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *OneOfWithDefaultsVariantPropertySchemaComponent) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 OneOfWithDefaultsVariantOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.OneOfWithDefaultsVariantOneOf0 = &v0 - successCount++ - } - - var v1 OneOfWithDefaultsVariantOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.OneOfWithDefaultsVariantOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("OneOfWithDefaultsVariantPropertySchemaComponent: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *OneOfWithDefaultsVariantPropertySchemaComponent) ApplyDefaults() { - if u.OneOfWithDefaultsVariantOneOf0 != nil { - u.OneOfWithDefaultsVariantOneOf0.ApplyDefaults() - } - if u.OneOfWithDefaultsVariantOneOf1 != nil { - u.OneOfWithDefaultsVariantOneOf1.ApplyDefaults() - } -} - -type OneOfWithDefaultsVariant = OneOfWithDefaultsVariantPropertySchemaComponent - -// #/components/schemas/OneOfWithDefaults/properties/variant/oneOf/0 -type OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent struct { - OptionA *string `json:"optionA,omitempty" form:"optionA,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent) ApplyDefaults() { - if s.OptionA == nil { - v := "option-a-default" - s.OptionA = &v - } -} - -type OneOfWithDefaultsVariantOneOf0 = OneOfWithDefaultsVariantN0OneOfPropertySchemaComponent - -// #/components/schemas/OneOfWithDefaults/properties/variant/oneOf/1 -type OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent struct { - OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent) ApplyDefaults() { - if s.OptionB == nil { - v := 123 - s.OptionB = &v - } -} - -type OneOfWithDefaultsVariantOneOf1 = OneOfWithDefaultsVariantN1OneOfPropertySchemaComponent - -// #/components/schemas/AllOfWithDefaults -type AllOfWithDefaultsSchemaComponent struct { - Base *string `json:"base,omitempty" form:"base,omitempty"` - Extended *int `json:"extended,omitempty" form:"extended,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithDefaultsSchemaComponent) ApplyDefaults() { - if s.Base == nil { - v := "base-value" - s.Base = &v - } - if s.Extended == nil { - v := 50 - s.Extended = &v - } -} - -type AllOfWithDefaults = AllOfWithDefaultsSchemaComponent - -// #/components/schemas/AllOfWithDefaults/allOf/0 -type AllOfWithDefaultsN0AllOfSchemaComponent struct { - Base *string `json:"base,omitempty" form:"base,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithDefaultsN0AllOfSchemaComponent) ApplyDefaults() { - if s.Base == nil { - v := "base-value" - s.Base = &v - } -} - -type AllOfWithDefaultsAllOf0 = AllOfWithDefaultsN0AllOfSchemaComponent - -// #/components/schemas/AllOfWithDefaults/allOf/1 -type AllOfWithDefaultsN1AllOfSchemaComponent struct { - Extended *int `json:"extended,omitempty" form:"extended,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithDefaultsN1AllOfSchemaComponent) ApplyDefaults() { - if s.Extended == nil { - v := 50 - s.Extended = &v - } -} - -type AllOfWithDefaultsAllOf1 = AllOfWithDefaultsN1AllOfSchemaComponent - -// #/components/schemas/DeepNesting -type DeepNestingSchemaComponent struct { - Level1 *DeepNestingLevel1 `json:"level1,omitempty" form:"level1,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DeepNestingSchemaComponent) ApplyDefaults() { - if s.Level1 != nil { - s.Level1.ApplyDefaults() - } -} - -type DeepNesting = DeepNestingSchemaComponent - -// #/components/schemas/DeepNesting/properties/level1 -type DeepNestingLevel1PropertySchemaComponent struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` - Level2 *DeepNestingLevel1Level2 `json:"level2,omitempty" form:"level2,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DeepNestingLevel1PropertySchemaComponent) ApplyDefaults() { - if s.Name == nil { - v := "level1-name" - s.Name = &v - } - if s.Level2 != nil { - s.Level2.ApplyDefaults() - } -} - -type DeepNestingLevel1 = DeepNestingLevel1PropertySchemaComponent - -// #/components/schemas/DeepNesting/properties/level1/properties/level2 -type DeepNestingLevel1Level2PropertyPropertySchemaComponent struct { - Count *int `json:"count,omitempty" form:"count,omitempty"` - Level3 *DeepNestingLevel1Level2Level3 `json:"level3,omitempty" form:"level3,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DeepNestingLevel1Level2PropertyPropertySchemaComponent) ApplyDefaults() { - if s.Count == nil { - v := 2 - s.Count = &v - } - if s.Level3 != nil { - s.Level3.ApplyDefaults() - } -} - -type DeepNestingLevel1Level2 = DeepNestingLevel1Level2PropertyPropertySchemaComponent - -// #/components/schemas/DeepNesting/properties/level1/properties/level2/properties/level3 -type DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent struct { - Enabled *bool `json:"enabled,omitempty" form:"enabled,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent) ApplyDefaults() { - if s.Enabled == nil { - v := false - s.Enabled = &v - } -} - -type DeepNestingLevel1Level2Level3 = DeepNestingLevel1Level2Level3PropertyPropertyPropertySchemaComponent - -// #/components/schemas/RequiredAndOptional -type RequiredAndOptionalSchemaComponent struct { - RequiredWithDefault string `json:"requiredWithDefault" form:"requiredWithDefault"` - RequiredNoDefault string `json:"requiredNoDefault" form:"requiredNoDefault"` - OptionalWithDefault *string `json:"optionalWithDefault,omitempty" form:"optionalWithDefault,omitempty"` - OptionalNoDefault *string `json:"optionalNoDefault,omitempty" form:"optionalNoDefault,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *RequiredAndOptionalSchemaComponent) ApplyDefaults() { - if s.OptionalWithDefault == nil { - v := "optional-default" - s.OptionalWithDefault = &v - } -} - -type RequiredAndOptional = RequiredAndOptionalSchemaComponent diff --git a/experimental/internal/codegen/test/default_values/output/default_values_test.go b/experimental/internal/codegen/test/default_values/output/default_values_test.go deleted file mode 100644 index ccee0f18e3..0000000000 --- a/experimental/internal/codegen/test/default_values/output/default_values_test.go +++ /dev/null @@ -1,324 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func ptr[T any](v T) *T { - return &v -} - -// TestSimpleDefaults tests ApplyDefaults on basic primitive types -func TestSimpleDefaults(t *testing.T) { - t.Run("applies all defaults to empty struct", func(t *testing.T) { - s := SimpleDefaults{} - s.ApplyDefaults() - - require.NotNil(t, s.StringField) - assert.Equal(t, "hello", *s.StringField) - - require.NotNil(t, s.IntField) - assert.Equal(t, 42, *s.IntField) - - require.NotNil(t, s.BoolField) - assert.Equal(t, true, *s.BoolField) - - require.NotNil(t, s.FloatField) - assert.Equal(t, float32(3.14), *s.FloatField) - - require.NotNil(t, s.Int64Field) - assert.Equal(t, int64(9223372036854775807), *s.Int64Field) - }) - - t.Run("does not overwrite existing values", func(t *testing.T) { - s := SimpleDefaults{ - StringField: ptr("custom"), - IntField: ptr(100), - BoolField: ptr(false), - FloatField: ptr(float32(1.5)), - Int64Field: ptr(int64(123)), - } - s.ApplyDefaults() - - assert.Equal(t, "custom", *s.StringField) - assert.Equal(t, 100, *s.IntField) - assert.Equal(t, false, *s.BoolField) - assert.Equal(t, float32(1.5), *s.FloatField) - assert.Equal(t, int64(123), *s.Int64Field) - }) - - t.Run("applies defaults after unmarshaling empty object", func(t *testing.T) { - input := `{}` - var s SimpleDefaults - err := json.Unmarshal([]byte(input), &s) - require.NoError(t, err) - - s.ApplyDefaults() - - assert.Equal(t, "hello", *s.StringField) - assert.Equal(t, 42, *s.IntField) - }) - - t.Run("applies defaults after unmarshaling partial object", func(t *testing.T) { - input := `{"stringField": "from-json"}` - var s SimpleDefaults - err := json.Unmarshal([]byte(input), &s) - require.NoError(t, err) - - s.ApplyDefaults() - - assert.Equal(t, "from-json", *s.StringField) // from JSON - assert.Equal(t, 42, *s.IntField) // from default - }) -} - -// TestNestedDefaults tests ApplyDefaults recursion into nested structs -func TestNestedDefaults(t *testing.T) { - t.Run("applies defaults to parent and recurses to children", func(t *testing.T) { - n := NestedDefaults{ - Child: &SimpleDefaults{}, - InlineChild: &NestedDefaultsInlineChild{}, - } - n.ApplyDefaults() - - // Parent defaults - require.NotNil(t, n.Name) - assert.Equal(t, "parent", *n.Name) - - // Child defaults (recursion) - require.NotNil(t, n.Child.StringField) - assert.Equal(t, "hello", *n.Child.StringField) - require.NotNil(t, n.Child.IntField) - assert.Equal(t, 42, *n.Child.IntField) - - // Inline child defaults (recursion) - require.NotNil(t, n.InlineChild.Label) - assert.Equal(t, "inline-default", *n.InlineChild.Label) - require.NotNil(t, n.InlineChild.Value) - assert.Equal(t, 100, *n.InlineChild.Value) - }) - - t.Run("does not recurse into nil children", func(t *testing.T) { - n := NestedDefaults{} - n.ApplyDefaults() - - // Parent defaults applied - require.NotNil(t, n.Name) - assert.Equal(t, "parent", *n.Name) - - // Children are still nil (not created) - assert.Nil(t, n.Child) - assert.Nil(t, n.InlineChild) - }) - - t.Run("applies defaults after unmarshaling nested JSON", func(t *testing.T) { - input := `{"child": {"stringField": "from-child"}, "inlineChild": {}}` - var n NestedDefaults - err := json.Unmarshal([]byte(input), &n) - require.NoError(t, err) - - n.ApplyDefaults() - - // Parent defaults - assert.Equal(t, "parent", *n.Name) - - // Child - one field from JSON, others from defaults - assert.Equal(t, "from-child", *n.Child.StringField) - assert.Equal(t, 42, *n.Child.IntField) - - // Inline child - all defaults - assert.Equal(t, "inline-default", *n.InlineChild.Label) - assert.Equal(t, 100, *n.InlineChild.Value) - }) -} - -// TestMapWithDefaults tests ApplyDefaults on structs with additionalProperties -func TestMapWithDefaults(t *testing.T) { - t.Run("applies defaults to known fields", func(t *testing.T) { - m := MapWithDefaults{} - m.ApplyDefaults() - - require.NotNil(t, m.Prefix) - assert.Equal(t, "map-", *m.Prefix) - }) - - t.Run("does not affect additional properties", func(t *testing.T) { - m := MapWithDefaults{ - AdditionalProperties: map[string]string{ - "extra": "value", - }, - } - m.ApplyDefaults() - - assert.Equal(t, "map-", *m.Prefix) - assert.Equal(t, "value", m.AdditionalProperties["extra"]) - }) -} - -// TestArrayDefaults tests ApplyDefaults on structs with array fields -func TestArrayDefaults(t *testing.T) { - t.Run("applies defaults to non-array fields", func(t *testing.T) { - a := ArrayDefaults{} - a.ApplyDefaults() - - require.NotNil(t, a.Count) - assert.Equal(t, 0, *a.Count) - // Array field is not touched (no default generation for arrays currently) - assert.Nil(t, a.Items) - }) -} - -// TestAnyOfWithDefaults tests ApplyDefaults on anyOf variant members -func TestAnyOfWithDefaults(t *testing.T) { - t.Run("applies defaults to anyOf variant 0", func(t *testing.T) { - v0 := AnyOfWithDefaultsValueAnyOf0{} - v0.ApplyDefaults() - - require.NotNil(t, v0.StringVal) - assert.Equal(t, "default-string", *v0.StringVal) - }) - - t.Run("applies defaults to anyOf variant 1", func(t *testing.T) { - v1 := AnyOfWithDefaultsValueAnyOf1{} - v1.ApplyDefaults() - - require.NotNil(t, v1.IntVal) - assert.Equal(t, 999, *v1.IntVal) - }) -} - -// TestOneOfWithDefaults tests ApplyDefaults on oneOf variant members -func TestOneOfWithDefaults(t *testing.T) { - t.Run("applies defaults to oneOf variant 0", func(t *testing.T) { - v0 := OneOfWithDefaultsVariantOneOf0{} - v0.ApplyDefaults() - - require.NotNil(t, v0.OptionA) - assert.Equal(t, "option-a-default", *v0.OptionA) - }) - - t.Run("applies defaults to oneOf variant 1", func(t *testing.T) { - v1 := OneOfWithDefaultsVariantOneOf1{} - v1.ApplyDefaults() - - require.NotNil(t, v1.OptionB) - assert.Equal(t, 123, *v1.OptionB) - }) -} - -// TestAllOfWithDefaults tests ApplyDefaults on allOf merged structs -func TestAllOfWithDefaults(t *testing.T) { - t.Run("applies defaults from all merged schemas", func(t *testing.T) { - a := AllOfWithDefaults{} - a.ApplyDefaults() - - // Default from allOf/0 - require.NotNil(t, a.Base) - assert.Equal(t, "base-value", *a.Base) - - // Default from allOf/1 - require.NotNil(t, a.Extended) - assert.Equal(t, 50, *a.Extended) - }) -} - -// TestDeepNesting tests ApplyDefaults recursion through multiple levels -func TestDeepNesting(t *testing.T) { - t.Run("recurses through all levels", func(t *testing.T) { - d := DeepNesting{ - Level1: &DeepNestingLevel1{ - Level2: &DeepNestingLevel1Level2{ - Level3: &DeepNestingLevel1Level2Level3{}, - }, - }, - } - d.ApplyDefaults() - - // Level 1 defaults - require.NotNil(t, d.Level1.Name) - assert.Equal(t, "level1-name", *d.Level1.Name) - - // Level 2 defaults - require.NotNil(t, d.Level1.Level2.Count) - assert.Equal(t, 2, *d.Level1.Level2.Count) - - // Level 3 defaults - require.NotNil(t, d.Level1.Level2.Level3.Enabled) - assert.Equal(t, false, *d.Level1.Level2.Level3.Enabled) - }) - - t.Run("stops at nil levels", func(t *testing.T) { - d := DeepNesting{ - Level1: &DeepNestingLevel1{ - // Level2 is nil - }, - } - d.ApplyDefaults() - - assert.Equal(t, "level1-name", *d.Level1.Name) - assert.Nil(t, d.Level1.Level2) - }) -} - -// TestRequiredAndOptional tests ApplyDefaults behavior with required fields -func TestRequiredAndOptional(t *testing.T) { - t.Run("applies defaults only to optional pointer fields", func(t *testing.T) { - r := RequiredAndOptional{ - RequiredWithDefault: "set-by-user", - RequiredNoDefault: "also-set", - } - r.ApplyDefaults() - - // Required fields are value types, not pointers, so they don't get defaults applied - assert.Equal(t, "set-by-user", r.RequiredWithDefault) - assert.Equal(t, "also-set", r.RequiredNoDefault) - - // Optional fields with defaults get defaults applied - require.NotNil(t, r.OptionalWithDefault) - assert.Equal(t, "optional-default", *r.OptionalWithDefault) - - // Optional fields without defaults stay nil - assert.Nil(t, r.OptionalNoDefault) - }) -} - -// TestApplyDefaultsIdempotent tests that ApplyDefaults can be called multiple times -func TestApplyDefaultsIdempotent(t *testing.T) { - t.Run("multiple calls have same effect", func(t *testing.T) { - s := SimpleDefaults{} - s.ApplyDefaults() - s.ApplyDefaults() - s.ApplyDefaults() - - assert.Equal(t, "hello", *s.StringField) - assert.Equal(t, 42, *s.IntField) - }) -} - -// TestApplyDefaultsChain tests typical usage pattern: unmarshal then apply defaults -func TestApplyDefaultsChain(t *testing.T) { - t.Run("unmarshal partial JSON then apply defaults", func(t *testing.T) { - input := `{ - "level1": { - "level2": { - "level3": {} - } - } - }` - - var d DeepNesting - err := json.Unmarshal([]byte(input), &d) - require.NoError(t, err) - - d.ApplyDefaults() - - // All defaults applied at all levels - assert.Equal(t, "level1-name", *d.Level1.Name) - assert.Equal(t, 2, *d.Level1.Level2.Count) - assert.Equal(t, false, *d.Level1.Level2.Level3.Enabled) - }) -} diff --git a/experimental/internal/codegen/test/external_ref/config.yaml b/experimental/internal/codegen/test/external_ref/config.yaml deleted file mode 100644 index 919d5b9d47..0000000000 --- a/experimental/internal/codegen/test/external_ref/config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -package: externalref -output: internal/codegen/test/external_ref/spec.gen.go -import-mapping: - ./packagea/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea - ./packageb/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb diff --git a/experimental/internal/codegen/test/external_ref/external_ref_test.go b/experimental/internal/codegen/test/external_ref/external_ref_test.go deleted file mode 100644 index 885ddb05bb..0000000000 --- a/experimental/internal/codegen/test/external_ref/external_ref_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package externalref - -import ( - "testing" - - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea" - "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" -) - -// TestCrossPackageReferences verifies that types from external packages -// can be used correctly in the Container type. -func TestCrossPackageReferences(t *testing.T) { - // Create objects from each package - name := "test-name" - b := &packageb.ObjectB{ - Name: &name, - } - - a := &packagea.ObjectA{ - Name: &name, - ObjectB: b, - } - - // Create container that references both - container := Container{ - ObjectA: a, - ObjectB: b, - } - - // Verify the structure - if container.ObjectA == nil { - t.Error("ObjectA should not be nil") - } - if container.ObjectB == nil { - t.Error("ObjectB should not be nil") - } - if *container.ObjectA.Name != "test-name" { - t.Errorf("ObjectA.Name = %q, want %q", *container.ObjectA.Name, "test-name") - } - if *container.ObjectB.Name != "test-name" { - t.Errorf("ObjectB.Name = %q, want %q", *container.ObjectB.Name, "test-name") - } - - // Verify nested reference in ObjectA - if container.ObjectA.ObjectB == nil { - t.Error("ObjectA.ObjectB should not be nil") - } - if *container.ObjectA.ObjectB.Name != "test-name" { - t.Errorf("ObjectA.ObjectB.Name = %q, want %q", *container.ObjectA.ObjectB.Name, "test-name") - } -} - -// TestApplyDefaults verifies that ApplyDefaults works across package boundaries. -func TestApplyDefaults(t *testing.T) { - container := Container{ - ObjectA: &packagea.ObjectA{}, - ObjectB: &packageb.ObjectB{}, - } - - // Should not panic when calling ApplyDefaults across packages - container.ApplyDefaults() -} diff --git a/experimental/internal/codegen/test/external_ref/packagea/config.yaml b/experimental/internal/codegen/test/external_ref/packagea/config.yaml deleted file mode 100644 index 7cacfcb822..0000000000 --- a/experimental/internal/codegen/test/external_ref/packagea/config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -package: packagea -output: internal/codegen/test/external_ref/packagea/spec.gen.go -import-mapping: - ../packageb/spec.yaml: github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb diff --git a/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go b/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go deleted file mode 100644 index b865bfb69d..0000000000 --- a/experimental/internal/codegen/test/external_ref/packagea/spec.gen.go +++ /dev/null @@ -1,22 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package packagea - -import ( - ext_a5fddf6c "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" -) - -// #/components/schemas/ObjectA -type ObjectASchemaComponent struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` - ObjectB *ext_a5fddf6c.ObjectB `json:"object_b,omitempty" form:"object_b,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectASchemaComponent) ApplyDefaults() { - if s.ObjectB != nil { - s.ObjectB.ApplyDefaults() - } -} - -type ObjectA = ObjectASchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/packagea/spec.yaml b/experimental/internal/codegen/test/external_ref/packagea/spec.yaml deleted file mode 100644 index 77f3ea45f5..0000000000 --- a/experimental/internal/codegen/test/external_ref/packagea/spec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -openapi: "3.1.0" -info: - title: Package A - version: "1.0" -paths: {} -components: - schemas: - ObjectA: - type: object - properties: - name: - type: string - object_b: - $ref: ../packageb/spec.yaml#/components/schemas/ObjectB diff --git a/experimental/internal/codegen/test/external_ref/packageb/config.yaml b/experimental/internal/codegen/test/external_ref/packageb/config.yaml deleted file mode 100644 index 7b36e2c291..0000000000 --- a/experimental/internal/codegen/test/external_ref/packageb/config.yaml +++ /dev/null @@ -1,2 +0,0 @@ -package: packageb -output: internal/codegen/test/external_ref/packageb/spec.gen.go diff --git a/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go b/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go deleted file mode 100644 index e72bf4ac99..0000000000 --- a/experimental/internal/codegen/test/external_ref/packageb/spec.gen.go +++ /dev/null @@ -1,14 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package packageb - -// #/components/schemas/ObjectB -type ObjectBSchemaComponent struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectBSchemaComponent) ApplyDefaults() { -} - -type ObjectB = ObjectBSchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/packageb/spec.yaml b/experimental/internal/codegen/test/external_ref/packageb/spec.yaml deleted file mode 100644 index bf9af943f5..0000000000 --- a/experimental/internal/codegen/test/external_ref/packageb/spec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -openapi: "3.1.0" -info: - title: Package B - version: "1.0" -paths: {} -components: - schemas: - ObjectB: - type: object - properties: - name: - type: string diff --git a/experimental/internal/codegen/test/external_ref/spec.gen.go b/experimental/internal/codegen/test/external_ref/spec.gen.go deleted file mode 100644 index cf179d426b..0000000000 --- a/experimental/internal/codegen/test/external_ref/spec.gen.go +++ /dev/null @@ -1,26 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package externalref - -import ( - ext_95d82e90 "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packagea" - ext_a5fddf6c "github.com/oapi-codegen/oapi-codegen/experimental/internal/codegen/test/external_ref/packageb" -) - -// #/components/schemas/Container -type ContainerSchemaComponent struct { - ObjectA *ext_95d82e90.ObjectA `json:"object_a,omitempty" form:"object_a,omitempty"` - ObjectB *ext_a5fddf6c.ObjectB `json:"object_b,omitempty" form:"object_b,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ContainerSchemaComponent) ApplyDefaults() { - if s.ObjectA != nil { - s.ObjectA.ApplyDefaults() - } - if s.ObjectB != nil { - s.ObjectB.ApplyDefaults() - } -} - -type Container = ContainerSchemaComponent diff --git a/experimental/internal/codegen/test/external_ref/spec.yaml b/experimental/internal/codegen/test/external_ref/spec.yaml deleted file mode 100644 index 5a8e0ada72..0000000000 --- a/experimental/internal/codegen/test/external_ref/spec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -openapi: "3.1.0" -info: - title: External Ref Test - version: "1.0" -paths: {} -components: - schemas: - Container: - type: object - properties: - object_a: - $ref: ./packagea/spec.yaml#/components/schemas/ObjectA - object_b: - $ref: ./packageb/spec.yaml#/components/schemas/ObjectB diff --git a/experimental/internal/codegen/test/files/comprehensive.yaml b/experimental/internal/codegen/test/files/comprehensive.yaml deleted file mode 100644 index 7bdef74eea..0000000000 --- a/experimental/internal/codegen/test/files/comprehensive.yaml +++ /dev/null @@ -1,861 +0,0 @@ -openapi: "3.1.0" -info: - title: Comprehensive Test Schema - version: "1.0.0" - description: Tests all schema patterns for oapi-codegen - -paths: - /simple: - get: - operationId: getSimple - responses: - "200": - description: Simple response - content: - application/json: - schema: - $ref: "#/components/schemas/SimpleObject" - - /inline-response: - get: - operationId: getInlineResponse - responses: - "200": - description: Inline object in response - content: - application/json: - schema: - type: object - required: - - id - - name - properties: - id: - type: integer - name: - type: string - - /parameters/{pathParam}: - parameters: - - name: pathParam - in: path - required: true - schema: - type: string - format: uuid - get: - operationId: getWithParameters - parameters: - - name: queryString - in: query - schema: - type: string - - name: queryInt - in: query - schema: - type: integer - - name: queryArray - in: query - schema: - type: array - items: - type: string - - name: headerParam - in: header - schema: - type: string - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/SimpleObject" - - /request-body: - post: - operationId: postRequestBody - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/AllTypesRequired" - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/SimpleObject" - - /multi-content: - post: - operationId: postMultiContent - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/SimpleObject" - application/x-www-form-urlencoded: - schema: - $ref: "#/components/schemas/SimpleObject" - multipart/form-data: - schema: - type: object - properties: - file: - type: string - format: binary - metadata: - type: string - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/SimpleObject" - text/plain: - schema: - type: string - -components: - schemas: - # =========================================== - # PRIMITIVE TYPES - All formats - # =========================================== - - AllTypesRequired: - type: object - required: - - intField - - int32Field - - int64Field - - floatField - - doubleField - - numberField - - stringField - - boolField - - dateField - - dateTimeField - - uuidField - - emailField - - uriField - - hostnameField - - ipv4Field - - ipv6Field - - byteField - - binaryField - - passwordField - properties: - intField: - type: integer - int32Field: - type: integer - format: int32 - int64Field: - type: integer - format: int64 - floatField: - type: number - format: float - doubleField: - type: number - format: double - numberField: - type: number - stringField: - type: string - boolField: - type: boolean - dateField: - type: string - format: date - dateTimeField: - type: string - format: date-time - uuidField: - type: string - format: uuid - emailField: - type: string - format: email - uriField: - type: string - format: uri - hostnameField: - type: string - format: hostname - ipv4Field: - type: string - format: ipv4 - ipv6Field: - type: string - format: ipv6 - byteField: - type: string - format: byte - binaryField: - type: string - format: binary - passwordField: - type: string - format: password - - AllTypesOptional: - type: object - properties: - intField: - type: integer - int32Field: - type: integer - format: int32 - int64Field: - type: integer - format: int64 - floatField: - type: number - format: float - doubleField: - type: number - format: double - numberField: - type: number - stringField: - type: string - boolField: - type: boolean - dateField: - type: string - format: date - dateTimeField: - type: string - format: date-time - uuidField: - type: string - format: uuid - emailField: - type: string - format: email - - # =========================================== - # NULLABLE TYPES - # =========================================== - - NullableRequired: - type: object - required: - - nullableString - - nullableInt - - nullableObject - properties: - nullableString: - type: - - string - - "null" - nullableInt: - type: - - integer - - "null" - nullableObject: - type: - - object - - "null" - properties: - name: - type: string - - NullableOptional: - type: object - properties: - nullableString: - type: - - string - - "null" - nullableInt: - type: - - integer - - "null" - - # =========================================== - # ARRAYS - # =========================================== - - ArrayTypes: - type: object - properties: - stringArray: - type: array - items: - type: string - intArray: - type: array - items: - type: integer - objectArray: - type: array - items: - $ref: "#/components/schemas/SimpleObject" - inlineObjectArray: - type: array - items: - type: object - properties: - id: - type: integer - name: - type: string - nestedArray: - type: array - items: - type: array - items: - type: string - nullableArray: - type: - - array - - "null" - items: - type: string - arrayWithConstraints: - type: array - minItems: 1 - maxItems: 10 - items: - type: string - - # =========================================== - # OBJECTS - # =========================================== - - SimpleObject: - type: object - required: - - id - properties: - id: - type: integer - name: - type: string - - NestedObject: - type: object - properties: - outer: - type: object - properties: - inner: - type: object - properties: - value: - type: string - - # =========================================== - # ADDITIONAL PROPERTIES - # =========================================== - - AdditionalPropsAny: - type: object - additionalProperties: true - - AdditionalPropsNone: - type: object - additionalProperties: false - properties: - known: - type: string - - AdditionalPropsTyped: - type: object - additionalProperties: - type: integer - - AdditionalPropsObject: - type: object - additionalProperties: - $ref: "#/components/schemas/SimpleObject" - - AdditionalPropsWithProps: - type: object - properties: - id: - type: integer - additionalProperties: - type: string - - # =========================================== - # ENUMS - # =========================================== - - StringEnum: - type: string - enum: - - value1 - - value2 - - value3 - - IntegerEnum: - type: integer - enum: - - 1 - - 2 - - 3 - - ObjectWithEnum: - type: object - properties: - status: - type: string - enum: - - pending - - active - - completed - priority: - type: integer - enum: - - 1 - - 2 - - 3 - - InlineEnumInProperty: - type: object - properties: - inlineStatus: - type: string - enum: - - on - - off - - # =========================================== - # ALLOF - Inheritance/Composition - # =========================================== - - BaseProperties: - type: object - properties: - id: - type: integer - createdAt: - type: string - format: date-time - - ExtendedObject: - allOf: - - $ref: "#/components/schemas/BaseProperties" - - type: object - required: - - name - properties: - name: - type: string - description: - type: string - - DeepInheritance: - allOf: - - $ref: "#/components/schemas/ExtendedObject" - - type: object - properties: - extra: - type: string - - AllOfMultipleRefs: - allOf: - - $ref: "#/components/schemas/BaseProperties" - - $ref: "#/components/schemas/SimpleObject" - - type: object - properties: - merged: - type: boolean - - AllOfInlineOnly: - allOf: - - type: object - properties: - first: - type: string - - type: object - properties: - second: - type: integer - - # =========================================== - # ANYOF - Union Types - # =========================================== - - AnyOfPrimitives: - anyOf: - - type: string - - type: integer - - AnyOfObjects: - anyOf: - - $ref: "#/components/schemas/SimpleObject" - - $ref: "#/components/schemas/BaseProperties" - - AnyOfMixed: - anyOf: - - type: string - - $ref: "#/components/schemas/SimpleObject" - - type: object - properties: - inline: - type: boolean - - AnyOfNullable: - anyOf: - - type: string - - type: "null" - - ObjectWithAnyOfProperty: - type: object - properties: - value: - anyOf: - - type: string - - type: integer - - type: boolean - - ArrayOfAnyOf: - type: array - items: - anyOf: - - $ref: "#/components/schemas/SimpleObject" - - $ref: "#/components/schemas/BaseProperties" - - # =========================================== - # ONEOF - Discriminated Unions - # =========================================== - - OneOfSimple: - oneOf: - - $ref: "#/components/schemas/SimpleObject" - - $ref: "#/components/schemas/BaseProperties" - - OneOfWithDiscriminator: - oneOf: - - $ref: "#/components/schemas/Cat" - - $ref: "#/components/schemas/Dog" - discriminator: - propertyName: petType - - OneOfWithDiscriminatorMapping: - oneOf: - - $ref: "#/components/schemas/Cat" - - $ref: "#/components/schemas/Dog" - discriminator: - propertyName: petType - mapping: - cat: "#/components/schemas/Cat" - dog: "#/components/schemas/Dog" - - Cat: - type: object - required: - - petType - - meow - properties: - petType: - type: string - meow: - type: string - whiskerLength: - type: number - - Dog: - type: object - required: - - petType - - bark - properties: - petType: - type: string - bark: - type: string - tailLength: - type: number - - OneOfInline: - oneOf: - - type: object - properties: - optionA: - type: string - - type: object - properties: - optionB: - type: integer - - OneOfPrimitives: - oneOf: - - type: string - - type: number - - type: boolean - - ObjectWithOneOfProperty: - type: object - properties: - id: - type: integer - variant: - oneOf: - - $ref: "#/components/schemas/Cat" - - $ref: "#/components/schemas/Dog" - discriminator: - propertyName: petType - - # =========================================== - # COMBINED COMPOSITION - # =========================================== - - AllOfWithOneOf: - allOf: - - $ref: "#/components/schemas/BaseProperties" - - oneOf: - - $ref: "#/components/schemas/Cat" - - $ref: "#/components/schemas/Dog" - discriminator: - propertyName: petType - - OneOfWithAllOf: - oneOf: - - allOf: - - $ref: "#/components/schemas/BaseProperties" - - type: object - properties: - variant: - type: string - const: "a" - - allOf: - - $ref: "#/components/schemas/BaseProperties" - - type: object - properties: - variant: - type: string - const: "b" - - # =========================================== - # RECURSIVE TYPES - # =========================================== - - TreeNode: - type: object - properties: - value: - type: string - children: - type: array - items: - $ref: "#/components/schemas/TreeNode" - - LinkedListNode: - type: object - properties: - value: - type: integer - next: - $ref: "#/components/schemas/LinkedListNode" - - RecursiveOneOf: - oneOf: - - type: string - - type: object - properties: - nested: - $ref: "#/components/schemas/RecursiveOneOf" - - # =========================================== - # READ/WRITE ONLY - # =========================================== - - ReadWriteOnly: - type: object - required: - - id - - password - properties: - id: - type: integer - readOnly: true - password: - type: string - writeOnly: true - name: - type: string - - # =========================================== - # DEFAULTS AND CONST - # =========================================== - - WithDefaults: - type: object - properties: - stringWithDefault: - type: string - default: "default_value" - intWithDefault: - type: integer - default: 42 - boolWithDefault: - type: boolean - default: true - arrayWithDefault: - type: array - items: - type: string - default: [] - - WithConst: - type: object - properties: - version: - type: string - const: "1.0.0" - type: - type: string - const: "fixed" - - # =========================================== - # CONSTRAINTS - # =========================================== - - WithConstraints: - type: object - properties: - boundedInt: - type: integer - minimum: 0 - maximum: 100 - exclusiveBoundedInt: - type: integer - exclusiveMinimum: 0 - exclusiveMaximum: 100 - multipleOf: - type: integer - multipleOf: 5 - boundedString: - type: string - minLength: 1 - maxLength: 255 - patternString: - type: string - pattern: "^[a-z]+$" - boundedArray: - type: array - minItems: 1 - maxItems: 10 - items: - type: string - uniqueArray: - type: array - uniqueItems: true - items: - type: string - - # =========================================== - # OPENAPI 3.1 SPECIFIC - # =========================================== - - TypeArray31: - type: - - object - - "null" - properties: - name: - type: string - - PrefixItems31: - type: array - prefixItems: - - type: string - - type: integer - - type: boolean - items: - type: string - - # =========================================== - # EMPTY / ANY TYPE - # =========================================== - - EmptySchema: {} - - AnyValue: - description: Accepts any JSON value - - ExplicitAny: - type: - - string - - number - - integer - - boolean - - array - - object - - "null" - - # =========================================== - # COMPLEX NESTED STRUCTURES - # =========================================== - - ComplexNested: - type: object - properties: - metadata: - type: object - additionalProperties: - anyOf: - - type: string - - type: integer - - type: array - items: - type: string - items: - type: array - items: - allOf: - - $ref: "#/components/schemas/BaseProperties" - - type: object - properties: - tags: - type: array - items: - type: string - config: - oneOf: - - type: object - properties: - mode: - type: string - const: "simple" - value: - type: string - - type: object - properties: - mode: - type: string - const: "advanced" - options: - type: object - additionalProperties: - type: string - - # =========================================== - # MAPS - # =========================================== - - StringMap: - type: object - additionalProperties: - type: string - - ObjectMap: - type: object - additionalProperties: - $ref: "#/components/schemas/SimpleObject" - - NestedMap: - type: object - additionalProperties: - type: object - additionalProperties: - type: string diff --git a/experimental/internal/codegen/test/issues/issue_1029/doc.go b/experimental/internal/codegen/test/issues/issue_1029/doc.go deleted file mode 100644 index dd7dc0eb30..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1029/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1029 tests that oneOf with multiple single-value string enums generates valid code. -// https://github.com/oapi-codegen/oapi-codegen/issues/1029 -package issue_1029 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go deleted file mode 100644 index 7c5a5d2fa1..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1029/output/types.gen.go +++ /dev/null @@ -1,186 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Registration -type Registration struct { - State *RegistrationState `json:"state,omitempty" form:"state,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Registration) ApplyDefaults() { -} - -// #/components/schemas/Registration/properties/state -type RegistrationState struct { - RegistrationStateOneOf0 *RegistrationStateOneOf0 - RegistrationStateOneOf1 *RegistrationStateOneOf1 - RegistrationStateOneOf2 *RegistrationStateOneOf2 - RegistrationStateOneOf3 *RegistrationStateOneOf3 -} - -func (u RegistrationState) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.RegistrationStateOneOf0 != nil { - count++ - data, err = json.Marshal(u.RegistrationStateOneOf0) - if err != nil { - return nil, err - } - } - if u.RegistrationStateOneOf1 != nil { - count++ - data, err = json.Marshal(u.RegistrationStateOneOf1) - if err != nil { - return nil, err - } - } - if u.RegistrationStateOneOf2 != nil { - count++ - data, err = json.Marshal(u.RegistrationStateOneOf2) - if err != nil { - return nil, err - } - } - if u.RegistrationStateOneOf3 != nil { - count++ - data, err = json.Marshal(u.RegistrationStateOneOf3) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("RegistrationState: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *RegistrationState) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 RegistrationStateOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.RegistrationStateOneOf0 = &v0 - successCount++ - } - - var v1 RegistrationStateOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.RegistrationStateOneOf1 = &v1 - successCount++ - } - - var v2 RegistrationStateOneOf2 - if err := json.Unmarshal(data, &v2); err == nil { - u.RegistrationStateOneOf2 = &v2 - successCount++ - } - - var v3 RegistrationStateOneOf3 - if err := json.Unmarshal(data, &v3); err == nil { - u.RegistrationStateOneOf3 = &v3 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("RegistrationState: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *RegistrationState) ApplyDefaults() { -} - -// #/components/schemas/Registration/properties/state/oneOf/0 -type RegistrationStateOneOf0 string - -const ( - RegistrationStateOneOf0_undefined RegistrationStateOneOf0 = "undefined" -) - -// #/components/schemas/Registration/properties/state/oneOf/1 -type RegistrationStateOneOf1 string - -const ( - RegistrationStateOneOf1_registered RegistrationStateOneOf1 = "registered" -) - -// #/components/schemas/Registration/properties/state/oneOf/2 -type RegistrationStateOneOf2 string - -const ( - RegistrationStateOneOf2_pending RegistrationStateOneOf2 = "pending" -) - -// #/components/schemas/Registration/properties/state/oneOf/3 -type RegistrationStateOneOf3 string - -const ( - RegistrationStateOneOf3_active RegistrationStateOneOf3 = "active" -) - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/6yQzY7UMBCE736KknJlMrPsibwBJySExNmb1CQNjm2527MaId4dOeFnZw4Iob25q7vr", - "a1eH96qVeDi9fTcgRX44Q61InMFYV8XZS2iVJcyMLN6IXFJmCVfXYTHLOhyPs9hSn/oxrcfksxzGNHFm", - "vC2kofTYWK5zHT4vjKja7Hfys9iCtQaTHIjWCDxcfKi8OeqN62ALfx80oRGgS6qhvdcsgfBxwnMqXzGm", - "UjhauPYuZUafZcBjf+ofncRzGhxgYoHDiyjwiWoOuLCopDjgoT/1J5e9LTrg23fXICkymrZ9HReufnsC", - "HzmLWvHWFjcFsGvmgPT0haP9lPYQTai/hgA1b/xTYo/lpQActgxutV2vceJZIqe73g7fA/xHq7L9geU1", - "vDLjdD/9X0Z+NLnwbz4/AgAA//+mSD78zgIAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go deleted file mode 100644 index 4ea2eabfbe..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1029/output/types_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestRegistrationStateOneOfEnums verifies that oneOf with string enums generates -// correctly with proper enum constants. -// https://github.com/oapi-codegen/oapi-codegen/issues/1029 -func TestRegistrationStateOneOfEnums(t *testing.T) { - // Verify enum constants exist and have correct values - tests := []struct { - name string - enum RegistrationStateOneOf0 - value string - }{ - {"undefined", RegistrationStateOneOf0_undefined, "undefined"}, - } - - for _, tt := range tests { - if string(tt.enum) != tt.value { - t.Errorf("%s enum = %q, want %q", tt.name, tt.enum, tt.value) - } - } -} - -func TestRegistrationStateMarshal(t *testing.T) { - // Test serialization of oneOf with string enum - state := RegistrationState{ - RegistrationStateOneOf0: ptrTo(RegistrationStateOneOf0(RegistrationStateOneOf0_undefined)), - } - - reg := Registration{ - State: &state, - } - - data, err := json.Marshal(reg) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - // Verify the JSON contains the expected value - expected := `{"state":"undefined"}` - if string(data) != expected { - t.Errorf("Marshal result = %s, want %s", string(data), expected) - } -} - -func TestRegistrationStateUnmarshalLimitation(t *testing.T) { - // Note: Unmarshaling oneOf with multiple string enum types is inherently - // ambiguous without a discriminator, since any string can match any of the - // enum types. This test documents that limitation. - input := `{"state":"undefined"}` - - var decoded Registration - err := json.Unmarshal([]byte(input), &decoded) - - // The error is expected because all 4 string enum types can unmarshal - // from the same string value - if err == nil { - t.Log("Unmarshal succeeded (all variants matched)") - } else { - t.Logf("Unmarshal failed as expected for ambiguous oneOf: %v", err) - } -} - -func TestAllEnumConstants(t *testing.T) { - // Verify all enum constants are defined - _ = RegistrationStateOneOf0_undefined - _ = RegistrationStateOneOf1_registered - _ = RegistrationStateOneOf2_pending - _ = RegistrationStateOneOf3_active - - // Test values - if string(RegistrationStateOneOf1_registered) != "registered" { - t.Error("registered enum has wrong value") - } - if string(RegistrationStateOneOf2_pending) != "pending" { - t.Error("pending enum has wrong value") - } - if string(RegistrationStateOneOf3_active) != "active" { - t.Error("active enum has wrong value") - } -} - -func ptrTo[T any](v T) *T { - return &v -} diff --git a/experimental/internal/codegen/test/issues/issue_1029/spec.yaml b/experimental/internal/codegen/test/issues/issue_1029/spec.yaml deleted file mode 100644 index 698973cfbb..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1029/spec.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Issue 1029: oneOf string enums failing to generate properly -# https://github.com/oapi-codegen/oapi-codegen/issues/1029 -# -# When using oneOf with multiple single-value string enums, -# the generated code should compile and work correctly. -openapi: 3.0.3 -info: - title: Issue 1029 Test - version: 1.0.0 -paths: {} -components: - schemas: - Registration: - type: object - properties: - state: - oneOf: - - enum: - - undefined - type: string - - enum: - - registered - type: string - - enum: - - pending - type: string - - enum: - - active - type: string diff --git a/experimental/internal/codegen/test/issues/issue_1039/doc.go b/experimental/internal/codegen/test/issues/issue_1039/doc.go deleted file mode 100644 index 64016470f8..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1039/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1039 tests nullable type generation. -// https://github.com/oapi-codegen/oapi-codegen/issues/1039 -package issue_1039 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go deleted file mode 100644 index d996cfb752..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1039/output/types.gen.go +++ /dev/null @@ -1,291 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/PatchRequest -// A request to patch an existing user object. -type PatchRequest struct { - SimpleRequiredNullable SimpleRequiredNullable `json:"simple_required_nullable" form:"simple_required_nullable"` - SimpleOptionalNullable SimpleOptionalNullable `json:"simple_optional_nullable,omitempty" form:"simple_optional_nullable,omitempty"` - SimpleOptionalNonNullable *any `json:"simple_optional_non_nullable,omitempty" form:"simple_optional_non_nullable,omitempty"` - ComplexRequiredNullable Nullable[ComplexRequiredNullable] `json:"complex_required_nullable" form:"complex_required_nullable"` - ComplexOptionalNullable Nullable[ComplexOptionalNullable] `json:"complex_optional_nullable,omitempty" form:"complex_optional_nullable,omitempty"` - AdditionalProperties map[string]any `json:"-"` -} - -func (s PatchRequest) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - result["simple_required_nullable"] = s.SimpleRequiredNullable - result["simple_optional_nullable"] = s.SimpleOptionalNullable - if s.SimpleOptionalNonNullable != nil { - result["simple_optional_non_nullable"] = s.SimpleOptionalNonNullable - } - result["complex_required_nullable"] = s.ComplexRequiredNullable - result["complex_optional_nullable"] = s.ComplexOptionalNullable - - // Add additional properties - for k, v := range s.AdditionalProperties { - result[k] = v - } - - return json.Marshal(result) -} - -func (s *PatchRequest) UnmarshalJSON(data []byte) error { - // Known fields - knownFields := map[string]bool{ - "simple_required_nullable": true, - "simple_optional_nullable": true, - "simple_optional_non_nullable": true, - "complex_required_nullable": true, - "complex_optional_nullable": true, - } - - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["simple_required_nullable"]; ok { - if err := json.Unmarshal(v, &s.SimpleRequiredNullable); err != nil { - return err - } - } - if v, ok := raw["simple_optional_nullable"]; ok { - if err := json.Unmarshal(v, &s.SimpleOptionalNullable); err != nil { - return err - } - } - if v, ok := raw["simple_optional_non_nullable"]; ok { - var val any - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.SimpleOptionalNonNullable = &val - } - if v, ok := raw["complex_required_nullable"]; ok { - if err := json.Unmarshal(v, &s.ComplexRequiredNullable); err != nil { - return err - } - } - if v, ok := raw["complex_optional_nullable"]; ok { - if err := json.Unmarshal(v, &s.ComplexOptionalNullable); err != nil { - return err - } - } - - // Collect additional properties - s.AdditionalProperties = make(map[string]any) - for k, v := range raw { - if !knownFields[k] { - var val any - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.AdditionalProperties[k] = val - } - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *PatchRequest) ApplyDefaults() { -} - -// #/components/schemas/simple_required_nullable -// Simple required and nullable -type SimpleRequiredNullable = Nullable[int] - -// #/components/schemas/simple_optional_nullable -// Simple optional and nullable -type SimpleOptionalNullable = Nullable[int] - -// #/components/schemas/complex_required_nullable -// Complex required and nullable -type ComplexRequiredNullable struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` // Optional and non nullable -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexRequiredNullable) ApplyDefaults() { -} - -// #/components/schemas/complex_optional_nullable -// Complex, optional and nullable -type ComplexOptionalNullable struct { - AliasName Nullable[string] `json:"alias_name,omitempty" form:"alias_name,omitempty"` // Optional and nullable - Name *string `json:"name,omitempty" form:"name,omitempty"` // Optional and non nullable -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ComplexOptionalNullable) ApplyDefaults() { -} - -// Nullable is a generic type that can distinguish between: -// - Field not provided (unspecified) -// - Field explicitly set to null -// - Field has a value -// -// This is implemented as a map[bool]T where: -// - Empty map: unspecified -// - map[false]T: explicitly null -// - map[true]T: has a value -type Nullable[T any] map[bool]T - -// NewNullableWithValue creates a Nullable with the given value. -func NewNullableWithValue[T any](value T) Nullable[T] { - return Nullable[T]{true: value} -} - -// NewNullNullable creates a Nullable that is explicitly null. -func NewNullNullable[T any]() Nullable[T] { - return Nullable[T]{false: *new(T)} -} - -// Get returns the value if set, or an error if null or unspecified. -func (n Nullable[T]) Get() (T, error) { - if v, ok := n[true]; ok { - return v, nil - } - var zero T - if n.IsNull() { - return zero, ErrNullableIsNull - } - return zero, ErrNullableNotSpecified -} - -// MustGet returns the value or panics if null or unspecified. -func (n Nullable[T]) MustGet() T { - v, err := n.Get() - if err != nil { - panic(err) - } - return v -} - -// Set assigns a value. -func (n *Nullable[T]) Set(value T) { - *n = Nullable[T]{true: value} -} - -// SetNull marks the field as explicitly null. -func (n *Nullable[T]) SetNull() { - *n = Nullable[T]{false: *new(T)} -} - -// SetUnspecified clears the field (as if it was never set). -func (n *Nullable[T]) SetUnspecified() { - *n = nil -} - -// IsNull returns true if the field is explicitly null. -func (n Nullable[T]) IsNull() bool { - if n == nil { - return false - } - _, ok := n[false] - return ok -} - -// IsSpecified returns true if the field was provided (either null or a value). -func (n Nullable[T]) IsSpecified() bool { - return len(n) > 0 -} - -// MarshalJSON implements json.Marshaler. -func (n Nullable[T]) MarshalJSON() ([]byte, error) { - if n.IsNull() { - return []byte("null"), nil - } - if v, ok := n[true]; ok { - return json.Marshal(v) - } - // Unspecified - this shouldn't be called if omitempty is used correctly - return []byte("null"), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (n *Nullable[T]) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - n.SetNull() - return nil - } - var v T - if err := json.Unmarshal(data, &v); err != nil { - return err - } - n.Set(v) - return nil -} - -// ErrNullableIsNull is returned when trying to get a value from a null Nullable. -var ErrNullableIsNull = errors.New("nullable value is null") - -// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. -var ErrNullableNotSpecified = errors.New("nullable value is not specified") - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/7RUTY/TMBC9+1eMEqReaNNlT+QGnFYIdgXcKzeZJl5S23gmqJX48SjfSZu0ge7eEnvm", - "vTdvxuPDA1GOcLe+fx/C1zzL5DZD4KNFggQ1OsnKaOFDymwpDIJEcZpvV5HZB0ZatYxMjAnq4Y8qQCko", - "UIUvfPgifyJQ7hA4lQx6yCMdNlwYg3XGosuOwljU0qoQ7lfr1Z1QemdCAfAbHSmjQ1isi/OFAGDFGYaA", - "B7m3GQqAGClyynIZ90cAwP9JsJJTKkiDGjsssazkKK0+AYrQ0qSHuJXwVATU9w5/5Uj80cTHJuVE4I8U", - "K0jYmvjYxhSJymEcArsc2+PIaEbNHRaAtDZTUSkieCaj+3cAFKW4l8MzgDcOdyF4fhCZvTUaNVNQRVJQ", - "yv9W6fbaMsgaTUgd0OLder3o4w6q8h4/e0J06EVgTVDl9FkalKIbIZjtM0YsRkA/NHYCm9ozqQEPiljp", - "BHJCV2evxImLrc4lkCqatGmuNs0w9EIK3RkeJmOqEWHV92MKtm+R3woCqWM4Y77cmCkG71SDKf2S2YSG", - "5voGDWcMFzQYPUuH0ctbtfSYvN6LmejlyzVmkuJcxSu2ZpKiUSHjWFVXT938wk5mhELMGeHqfSrNmKCr", - "z9qY/p4avNrvJeqEwWLO2N7EO26pmDuqFTexUzqZzWL0CdPVIRxZfdcr/FShXpzdsVWl5R4nN/fjZCVd", - "wsAUMWu+r+32upa3F5/AWDEyU5I2/1DSlXK649EGvLR7o1R/AwAA///zkywGmQkAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go deleted file mode 100644 index f165ca7ce8..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1039/output/types_test.go +++ /dev/null @@ -1,266 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestNullableTypes verifies that nullable types are generated properly. -// https://github.com/oapi-codegen/oapi-codegen/issues/1039 -// -// The implementation uses Nullable[T] for nullable types: -// - Nullable primitive schemas generate type aliases: type SimpleRequiredNullable = Nullable[int] -// - Nullable object fields are wrapped: Nullable[ComplexType] -// - Inline nullable primitives use Nullable[T] directly -func TestNullableTypes(t *testing.T) { - // Create a patch request with various nullable fields - name := "test-name" - - // SimpleRequiredNullable is Nullable[int] - simpleRequired := NewNullableWithValue(42) - - // ComplexRequiredNullable is wrapped in Nullable - complexRequired := NewNullableWithValue(ComplexRequiredNullable{Name: &name}) - - req := PatchRequest{ - SimpleRequiredNullable: simpleRequired, - ComplexRequiredNullable: complexRequired, - } - - // Verify simple nullable value - val, err := req.SimpleRequiredNullable.Get() - if err != nil { - t.Fatalf("SimpleRequiredNullable.Get() failed: %v", err) - } - if val != 42 { - t.Errorf("SimpleRequiredNullable = %v, want 42", val) - } - - // Verify complex nullable can retrieve value - complexVal, err := req.ComplexRequiredNullable.Get() - if err != nil { - t.Fatalf("ComplexRequiredNullable.Get() failed: %v", err) - } - if *complexVal.Name != "test-name" { - t.Errorf("ComplexRequiredNullable.Name = %q, want %q", *complexVal.Name, "test-name") - } -} - -func TestPatchRequestJSONRoundTrip(t *testing.T) { - name := "test" - original := PatchRequest{ - SimpleRequiredNullable: NewNullableWithValue(100), - ComplexRequiredNullable: NewNullableWithValue(ComplexRequiredNullable{Name: &name}), - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - t.Logf("Marshaled: %s", string(data)) - - var decoded PatchRequest - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - // Verify simple nullable round-trips correctly - decodedSimple, err := decoded.SimpleRequiredNullable.Get() - if err != nil { - t.Fatalf("SimpleRequiredNullable.Get() failed: %v", err) - } - if decodedSimple != 100 { - t.Errorf("SimpleRequiredNullable mismatch: got %v, want %v", decodedSimple, 100) - } - - // Verify complex nullable round-trips correctly - complexVal, err := decoded.ComplexRequiredNullable.Get() - if err != nil { - t.Fatalf("ComplexRequiredNullable.Get() failed: %v", err) - } - if *complexVal.Name != "test" { - t.Errorf("ComplexRequiredNullable.Name = %q, want %q", *complexVal.Name, "test") - } -} - -func TestComplexNullableTypes(t *testing.T) { - // Complex nullable types use Nullable[T] - name := "name" - opt := ComplexOptionalNullable{ - AliasName: NewNullableWithValue("alias"), - Name: &name, - } - - req := PatchRequest{ - SimpleRequiredNullable: NewNullNullable[int](), // explicitly null - ComplexRequiredNullable: NewNullNullable[ComplexRequiredNullable](), - ComplexOptionalNullable: NewNullableWithValue(opt), - } - - // Check the complex optional nullable - if !req.ComplexOptionalNullable.IsSpecified() { - t.Fatal("ComplexOptionalNullable should be specified") - } - optVal := req.ComplexOptionalNullable.MustGet() - aliasVal := optVal.AliasName.MustGet() - if aliasVal != "alias" { - t.Errorf("AliasName = %q, want %q", aliasVal, "alias") - } - - // Check that required nullable can be null - if !req.ComplexRequiredNullable.IsNull() { - t.Error("ComplexRequiredNullable should be null") - } - if !req.SimpleRequiredNullable.IsNull() { - t.Error("SimpleRequiredNullable should be null") - } -} - -func TestNullableThreeStates(t *testing.T) { - // Test unspecified (nil/empty map) - unspecified := Nullable[string](nil) - if unspecified.IsSpecified() { - t.Error("unspecified should not be specified") - } - if unspecified.IsNull() { - t.Error("unspecified should not be null") - } - _, err := unspecified.Get() - if err != ErrNullableNotSpecified { - t.Errorf("Get() on unspecified should return ErrNullableNotSpecified, got %v", err) - } - - // Test explicitly null - null := NewNullNullable[string]() - if !null.IsSpecified() { - t.Error("null should be specified") - } - if !null.IsNull() { - t.Error("null should be null") - } - _, err = null.Get() - if err != ErrNullableIsNull { - t.Errorf("Get() on null should return ErrNullableIsNull, got %v", err) - } - - // Test with value - withValue := NewNullableWithValue("hello") - if !withValue.IsSpecified() { - t.Error("withValue should be specified") - } - if withValue.IsNull() { - t.Error("withValue should not be null") - } - val, err := withValue.Get() - if err != nil { - t.Errorf("Get() on withValue should succeed, got %v", err) - } - if val != "hello" { - t.Errorf("Get() = %q, want %q", val, "hello") - } -} - -func TestNullableJSONMarshal(t *testing.T) { - // Test marshaling each state - tests := []struct { - name string - nullable Nullable[string] - want string - }{ - {"with value", NewNullableWithValue("test"), `"test"`}, - {"explicitly null", NewNullNullable[string](), "null"}, - {"unspecified", Nullable[string](nil), "null"}, // unspecified marshals as null - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - data, err := json.Marshal(tt.nullable) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - if string(data) != tt.want { - t.Errorf("Marshal() = %s, want %s", string(data), tt.want) - } - }) - } -} - -func TestNullableJSONUnmarshal(t *testing.T) { - tests := []struct { - name string - json string - wantNull bool - wantValue string - wantErr error - }{ - {"with value", `"test"`, false, "test", nil}, - {"explicitly null", "null", true, "", ErrNullableIsNull}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var n Nullable[string] - if err := json.Unmarshal([]byte(tt.json), &n); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - if n.IsNull() != tt.wantNull { - t.Errorf("IsNull() = %v, want %v", n.IsNull(), tt.wantNull) - } - val, err := n.Get() - if err != tt.wantErr { - t.Errorf("Get() error = %v, want %v", err, tt.wantErr) - } - if err == nil && val != tt.wantValue { - t.Errorf("Get() = %q, want %q", val, tt.wantValue) - } - }) - } -} - -// TestNullablePrimitiveTypeAlias verifies that nullable primitive schemas -// generate proper type aliases. -func TestNullablePrimitiveTypeAlias(t *testing.T) { - // SimpleRequiredNullable should be a type alias to Nullable[int] - var simple SimpleRequiredNullable - simple.Set(42) - - val, err := simple.Get() - if err != nil { - t.Fatalf("Get() failed: %v", err) - } - if val != 42 { - t.Errorf("Get() = %d, want 42", val) - } - - // Test null state - simple.SetNull() - if !simple.IsNull() { - t.Error("should be null after SetNull()") - } - - // Test unspecified state - simple.SetUnspecified() - if simple.IsSpecified() { - t.Error("should not be specified after SetUnspecified()") - } -} - -// TestAdditionalPropertiesFalse verifies that additionalProperties: false -// generates proper marshal/unmarshal that rejects extra fields. -func TestAdditionalPropertiesFalse(t *testing.T) { - // The struct has AdditionalProperties field but additionalProperties: false - // means unknown fields are still collected but not expected - req := PatchRequest{ - SimpleRequiredNullable: NewNullableWithValue(1), - ComplexRequiredNullable: NewNullNullable[ComplexRequiredNullable](), - AdditionalProperties: map[string]any{"extra": "value"}, - } - - // Should marshal with additional properties - data, err := json.Marshal(req) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - t.Logf("Marshaled: %s", string(data)) -} diff --git a/experimental/internal/codegen/test/issues/issue_1039/spec.yaml b/experimental/internal/codegen/test/issues/issue_1039/spec.yaml deleted file mode 100644 index 8d827acef5..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1039/spec.yaml +++ /dev/null @@ -1,86 +0,0 @@ -# Issue 1039: Nullable types generation -# https://github.com/oapi-codegen/oapi-codegen/issues/1039 -# -# Make sure that nullable types are generated properly -openapi: 3.0.1 -info: - version: '0.0.1' - title: example - description: | - Make sure that nullable types are generated properly -paths: - /example: - patch: - operationId: examplePatch - requestBody: - description: The patch body - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/PatchRequest" - responses: - '200': - description: "OK" - -components: - schemas: - PatchRequest: - type: object - description: A request to patch an existing user object. - required: - - simple_required_nullable - - complex_required_nullable - properties: - simple_required_nullable: - # required and nullable - $ref: "#/components/schemas/simple_required_nullable" - simple_optional_nullable: - # optional and nullable - $ref: "#/components/schemas/simple_optional_nullable" - simple_optional_non_nullable: - # optional and non-nullable - $ref: "#/components/schemas/simple_optional_non_nullable" - complex_required_nullable: - # required and nullable - $ref: "#/components/schemas/complex_required_nullable" - complex_optional_nullable: - # optional and nullable - $ref: "#/components/schemas/complex_optional_nullable" - additionalProperties: false - - simple_required_nullable: - type: integer - nullable: true - description: Simple required and nullable - - simple_optional_nullable: - type: integer - nullable: true - description: Simple optional and nullable - - simple_optional_non_nullable: - type: string - description: Simple optional and non nullable - - complex_required_nullable: - type: object - nullable: true - description: Complex required and nullable - properties: - name: - description: Optional and non nullable - type: string - - complex_optional_nullable: - type: object - description: Complex, optional and nullable - properties: - alias_name: - description: Optional and nullable - type: string - nullable: true - name: - description: Optional and non nullable - type: string - nullable: true diff --git a/experimental/internal/codegen/test/issues/issue_1397/doc.go b/experimental/internal/codegen/test/issues/issue_1397/doc.go deleted file mode 100644 index 94fef2bfb0..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1397/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1397 tests basic type generation with x-go-type-name. -// https://github.com/oapi-codegen/oapi-codegen/issues/1397 -package issue_1397 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go deleted file mode 100644 index 7fd6bbf827..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1397/output/types.gen.go +++ /dev/null @@ -1,114 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Test -type MyTestRequest struct { - Field1 []TestField1Item `json:"field1,omitempty" form:"field1,omitempty"` // A array of enum values - Field2 *MyTestRequestNestedField `json:"field2,omitempty" form:"field2,omitempty"` // A nested object with allocated name - Field3 *TestField3 `json:"field3,omitempty" form:"field3,omitempty"` // A nested object without allocated name -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *MyTestRequest) ApplyDefaults() { - if s.Field2 != nil { - s.Field2.ApplyDefaults() - } - if s.Field3 != nil { - s.Field3.ApplyDefaults() - } -} - -// #/components/schemas/Test/properties/field1 -// A array of enum values -type TestField1 = []TestField1Item - -// #/components/schemas/Test/properties/field1/items -type TestField1Item string - -const ( - TestField1Item_option1 TestField1Item = "option1" - TestField1Item_option2 TestField1Item = "option2" -) - -// #/components/schemas/Test/properties/field2 -// A nested object with allocated name -type MyTestRequestNestedField struct { - Field1 bool `json:"field1" form:"field1"` - Field2 string `json:"field2" form:"field2"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *MyTestRequestNestedField) ApplyDefaults() { -} - -// #/components/schemas/Test/properties/field3 -// A nested object without allocated name -type TestField3 struct { - Field1 bool `json:"field1" form:"field1"` - Field2 string `json:"field2" form:"field2"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestField3) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/9xUzZKbMAy+8xSapFdCIO106lv30Jkc2kOnL+AYBbwDltcS283bd2zYAJt0Z3otJ/xZ", - "P58+WdrCkXlAKA9fPit40GwNyMUjNOgwaLHk4LeVFl7yhvJ4kzvdY7aFVsSzKorGSjucdob6grS3uaEa", - "G3Trg41JuIhZMvLotLcKNofdflduMuvOpDIAsdKhWhCCX8iSATxjYEtOQbnb7/aZod6TQyccvdi02Ov0", - "C8lh/INUhgI6PaKRCfKBPAaxyK9GAGeLXV3OZ4Aa2QTrJaX8CjoEfQE6A7qhh2fdDcgLayvY89IdkuEa", - "yYFSvPIuWq3QkTdLsK5ZXPT65ZhSwaclat2E7rO3IRLxdZ3VO3U6ZMF6Emxsuu46Mjqiqemz6z0h74s5", - "0zkRdajdrX113/5GgYBPgw1YL83zKeUtVN3osXoK8Vu/aQXfL/H9/MSnAVl+JDm+xVBrDQ//pCEN8j/L", - "+K6EmdfSptIKuQ5mg9cJjcWnFXOsFcg4668MkeWB6stM0pATdLJkrb3vrEkRikcmtxZgXAxvRfkQ8Kxg", - "sy3mLVJMK6SI1DdXDuzJ8bIz1f7jX1vfENXZnwAAAP//PTfE300FAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go deleted file mode 100644 index 05ae316ffb..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1397/output/types_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestNestedObjectTypes verifies that nested objects get proper types. -// https://github.com/oapi-codegen/oapi-codegen/issues/1397 -// -// Note: The x-go-type-name extension is not currently supported. Types are -// named based on their path in the schema rather than the specified names. -func TestNestedObjectTypes(t *testing.T) { - // Test schema should have array of enums, and two nested objects - test := MyTestRequest{ - Field1: []TestField1Item{ - TestField1Item_option1, - TestField1Item_option2, - }, - Field2: &MyTestRequestNestedField{ - Field1: true, - Field2: "value2", - }, - Field3: &TestField3{ - Field1: false, - Field2: "value3", - }, - } - - if len(test.Field1) != 2 { - t.Errorf("Field1 length = %d, want 2", len(test.Field1)) - } - if test.Field2.Field1 != true { - t.Errorf("Field2.Field1 = %v, want true", test.Field2.Field1) - } - if test.Field3.Field2 != "value3" { - t.Errorf("Field3.Field2 = %q, want %q", test.Field3.Field2, "value3") - } -} - -func TestEnumArrayField(t *testing.T) { - // Field1 is an array of enum values - _ = TestField1Item_option1 - _ = TestField1Item_option2 - - items := []TestField1Item{ - TestField1Item("option1"), - TestField1Item("option2"), - } - - if len(items) != 2 { - t.Errorf("items length = %d, want 2", len(items)) - } -} - -func TestTestJSONRoundTrip(t *testing.T) { - original := MyTestRequest{ - Field1: []TestField1Item{TestField1Item_option1}, - Field2: &MyTestRequestNestedField{Field1: true, Field2: "test"}, - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded MyTestRequest - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if len(decoded.Field1) != 1 { - t.Errorf("Field1 length = %d, want 1", len(decoded.Field1)) - } - if decoded.Field2 == nil { - t.Fatal("Field2 should not be nil") - } - if decoded.Field2.Field1 != true { - t.Errorf("Field2.Field1 = %v, want true", decoded.Field2.Field1) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_1397/spec.yaml b/experimental/internal/codegen/test/issues/issue_1397/spec.yaml deleted file mode 100644 index 3f1289ceac..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1397/spec.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# Issue 1397: Basic type generation with x-go-type-name -# https://github.com/oapi-codegen/oapi-codegen/issues/1397 -openapi: "3.0.1" -info: - title: Issue 1397 Test - version: 1.0.0 -components: - schemas: - Test: - type: object - properties: - field1: - description: A array of enum values - items: - enum: - - option1 - - option2 - type: string - maxItems: 5 - minItems: 0 - type: array - field2: - description: A nested object with allocated name - properties: - field1: - type: boolean - field2: - type: string - required: - - field1 - - field2 - type: object - x-go-type-name: MyTestRequestNestedField - field3: - description: A nested object without allocated name - properties: - field1: - type: boolean - field2: - type: string - required: - - field1 - - field2 - type: object - x-go-type-name: MyTestRequest -paths: - /test: - get: - operationId: test - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/Test" - responses: - 204: - description: good diff --git a/experimental/internal/codegen/test/issues/issue_1429/doc.go b/experimental/internal/codegen/test/issues/issue_1429/doc.go deleted file mode 100644 index ab6cbd6e21..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1429/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1429 tests that enums inside anyOf members are generated. -// https://github.com/oapi-codegen/oapi-codegen/issues/1429 -package issue_1429 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go deleted file mode 100644 index 993992b0d7..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1429/output/types.gen.go +++ /dev/null @@ -1,149 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/test -type Test struct { - TestAnyOf0 *TestAnyOf0 - TestAnyOf1 *TestAnyOf1 -} - -func (u Test) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.TestAnyOf0 != nil { - data, err := json.Marshal(u.TestAnyOf0) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.TestAnyOf1 != nil { - data, err := json.Marshal(u.TestAnyOf1) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *Test) UnmarshalJSON(data []byte) error { - var v0 TestAnyOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.TestAnyOf0 = &v0 - } - - var v1 TestAnyOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.TestAnyOf1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *Test) ApplyDefaults() { - if u.TestAnyOf0 != nil { - u.TestAnyOf0.ApplyDefaults() - } - if u.TestAnyOf1 != nil { - u.TestAnyOf1.ApplyDefaults() - } -} - -// #/components/schemas/test/anyOf/0 -type TestAnyOf0 struct { - FieldA *string `json:"fieldA,omitempty" form:"fieldA,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestAnyOf0) ApplyDefaults() { -} - -// #/components/schemas/test/anyOf/1 -type TestAnyOf1 struct { - FieldA *string `json:"fieldA,omitempty" form:"fieldA,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestAnyOf1) ApplyDefaults() { -} - -// #/components/schemas/test/anyOf/1/properties/fieldA -type TestAnyOf1FieldA string - -const ( - TestAnyOf1FieldA_foo TestAnyOf1FieldA = "foo" - TestAnyOf1FieldA_bar TestAnyOf1FieldA = "bar" -) - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/6xSsW7cMAzd9RUPcYEsvfMl7VJtHTN1KdBZtmlLwZkURLrF/X0hOwdfrh3DiXqkHt8T", - "1eBFdSE8fX3+5kG8zGAxTMRUgtGAP5EYi9YsWUTgy4/RNYhmWX3bTsni0h17mVsJOR16GWgifn9IdYS2", - "dYZrXINflTMgF8lU7ILEmgZC4I0eM80dFcSgFauiPsMibfLsksk10CjLeUBHu9ajk0wccvL4cjwdTy7x", - "KN4BluxM/sYpfpKaA35T0STs8bT252BR64XWSK0mwERvCVDVBkvCL4O/MtQopFlYSa+NwMPz6fSwH4Fe", - "2IjtFgJCzufUr5Ttqwq/rwLaR5rDPQp8KjR6PDZtL3MWJjZtt15dlT+6vVBvv9U2ot0a1rf0kO6V+quZ", - "dQP7yMN1S+nWXo0x0Xn4fi9uY1QriaePJdmifoF/H+SAUeQ/aBeK+xsAAP//dJpKJ+ICAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go deleted file mode 100644 index 9020a645b2..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1429/output/types_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestEnumGenerated verifies that the enum type is generated for properties inside anyOf. -// Issue 1429: enum type was not being generated when used inside anyOf. -func TestEnumGenerated(t *testing.T) { - // The enum type should exist and have the expected constants - _ = TestAnyOf1FieldA_foo - _ = TestAnyOf1FieldA_bar - - // The alias should also exist - _ = TestAnyOf1FieldA(TestAnyOf1FieldA_foo) -} - -// TestAnyOfMarshal verifies that the anyOf type can be marshaled. -func TestAnyOfMarshal(t *testing.T) { - test := Test{ - TestAnyOf1: &TestAnyOf1{ - FieldA: ptr("foo"), - }, - } - - data, err := json.Marshal(test) - if err != nil { - t.Fatalf("Failed to marshal: %v", err) - } - - t.Logf("Marshaled: %s", string(data)) -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/experimental/internal/codegen/test/issues/issue_1429/spec.yaml b/experimental/internal/codegen/test/issues/issue_1429/spec.yaml deleted file mode 100644 index a07aef195a..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1429/spec.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Issue 1429: enum not generated when used with anyOf -# https://github.com/oapi-codegen/oapi-codegen/issues/1429 -# -# When a property inside an anyOf member has an enum, the enum type -# should be generated. -openapi: 3.0.0 -info: - title: Issue 1429 Test - version: 1.0.0 -paths: - /test: - get: - operationId: Test - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/test' -components: - schemas: - test: - type: object - anyOf: - - properties: - fieldA: - type: string - - properties: - fieldA: - type: string - enum: - - foo - - bar diff --git a/experimental/internal/codegen/test/issues/issue_1496/doc.go b/experimental/internal/codegen/test/issues/issue_1496/doc.go deleted file mode 100644 index e09cb2f78e..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1496/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1496 tests that inline schemas generate valid Go identifiers. -// https://github.com/oapi-codegen/oapi-codegen/issues/1496 -package issue_1496 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go deleted file mode 100644 index 2f95e2dbf8..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1496/output/types.gen.go +++ /dev/null @@ -1,168 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" -) - -// #/paths//something/get/responses/200/content/application/json/schema -type GetSomethingJSONResponse struct { - Results []GetSomething200ResponseJSON2 `json:"results" form:"results"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *GetSomethingJSONResponse) ApplyDefaults() { -} - -// #/paths//something/get/responses/200/content/application/json/schema/properties/results -type GetSomething200ResponseJSON1 = []GetSomething200ResponseJSON2 - -// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items -type GetSomething200ResponseJSON2 struct { - GetSomething200ResponseJSONAnyOf0 *GetSomething200ResponseJSONAnyOf0 - GetSomething200ResponseJSONAnyOf11 *GetSomething200ResponseJSONAnyOf11 -} - -func (u GetSomething200ResponseJSON2) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.GetSomething200ResponseJSONAnyOf0 != nil { - data, err := json.Marshal(u.GetSomething200ResponseJSONAnyOf0) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - if u.GetSomething200ResponseJSONAnyOf11 != nil { - data, err := json.Marshal(u.GetSomething200ResponseJSONAnyOf11) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *GetSomething200ResponseJSON2) UnmarshalJSON(data []byte) error { - var v0 GetSomething200ResponseJSONAnyOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.GetSomething200ResponseJSONAnyOf0 = &v0 - } - - var v1 GetSomething200ResponseJSONAnyOf11 - if err := json.Unmarshal(data, &v1); err == nil { - u.GetSomething200ResponseJSONAnyOf11 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *GetSomething200ResponseJSON2) ApplyDefaults() { - if u.GetSomething200ResponseJSONAnyOf0 != nil { - u.GetSomething200ResponseJSONAnyOf0.ApplyDefaults() - } - if u.GetSomething200ResponseJSONAnyOf11 != nil { - u.GetSomething200ResponseJSONAnyOf11.ApplyDefaults() - } -} - -// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/0 -type GetSomething200ResponseJSONAnyOf0 struct { - Order *string `json:"order,omitempty" form:"order,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *GetSomething200ResponseJSONAnyOf0) ApplyDefaults() { -} - -// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/1 -type GetSomething200ResponseJSONAnyOf11 struct { - Error *GetSomething200ResponseJSONAnyOf12 `json:"error,omitempty" form:"error,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *GetSomething200ResponseJSONAnyOf11) ApplyDefaults() { - if s.Error != nil { - s.Error.ApplyDefaults() - } -} - -// #/paths//something/get/responses/200/content/application/json/schema/properties/results/items/anyOf/1/properties/error -type GetSomething200ResponseJSONAnyOf12 struct { - Code *float32 `json:"code,omitempty" form:"code,omitempty"` - Message *string `json:"message,omitempty" form:"message,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *GetSomething200ResponseJSONAnyOf12) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/7xTTW+bQBC98yue4ksrJeC0VaVy66nyKVJTqcdoDWOYyMxud4ZY/vfVgqlJncTJJZyY", - "fTP7PhgWWKn2hOsv376W+C5e9p3vFX59T5VBq5Y6hx1bCy90s0FDQtEZKVge3JZrcE1ivGGK2QKtWdCy", - "KBq2tl/nle8K7wJfVb6mhuRxwYlai8SdLbIFfrckcAKWLQtN5CxwiKTBixJ6JYWT/c2mGARdwlr6p6qG", - "7QNBXEfZAjunUHPRWJrRg4P03ZoiPlDe5Jf4tFze/STtt6Z3K6PuI3YtVy14Zk/ww+eZDyQucInP+TJf", - "ZiwbX2aAsW2pnIWIX6SWAQ8Ulb2UuB76g7NW00ChviNrWZpUAQ3Z+AL4kDywl1VdpvPbqfOATxnoNICk", - "/1gANWkVOdhAfHHbVxWpXswaKi9GYvMZwIWw5WpgLu7Vy2MUh+/w/ymGqMvDppyAkf70HKk+HQOukpWU", - "+QkWYgrBeO5xfucw9RQ0qXExuv2TOBt1z4xiXKjnwCT4Ra+v1X98fKwpvtwyOVKLxxV4B2kUo3+ltLOc", - "b+Ed17Om810T/fgrn23vSNU1b7j3kPjfAAAA///mDrwBGwUAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go deleted file mode 100644 index 5056b4583e..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1496/output/types_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestValidIdentifiers verifies that all generated type names are valid Go identifiers. -// Issue 1496: Inline schemas in responses were generating identifiers starting with numbers. -func TestValidIdentifiers(t *testing.T) { - // If this compiles, the identifiers are valid - response := GetSomethingJSONResponse{ - Results: []GetSomething200ResponseJSON2{ - { - GetSomething200ResponseJSONAnyOf0: &GetSomething200ResponseJSONAnyOf0{ - Order: ptr("order-123"), - }, - }, - { - GetSomething200ResponseJSONAnyOf11: &GetSomething200ResponseJSONAnyOf11{ - Error: &GetSomething200ResponseJSONAnyOf12{ - Code: ptr(float32(400)), - Message: ptr("Bad request"), - }, - }, - }, - }, - } - - // Should be able to marshal - data, err := json.Marshal(response) - if err != nil { - t.Fatalf("Failed to marshal response: %v", err) - } - - t.Logf("Marshaled response: %s", string(data)) -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/experimental/internal/codegen/test/issues/issue_1496/spec.yaml b/experimental/internal/codegen/test/issues/issue_1496/spec.yaml deleted file mode 100644 index f4156e97ad..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1496/spec.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Issue 1496: Anonymous object schema with oneOf generates invalid identifier -# https://github.com/oapi-codegen/oapi-codegen/issues/1496 -# -# When an inline schema in a response uses anyOf/oneOf, the generated type name -# was starting with a number (e.g., 200_Results_Item) which is invalid in Go. -openapi: 3.0.0 -info: - title: Issue 1496 Test - version: 1.0.0 -paths: - /something: - get: - operationId: getSomething - responses: - 200: - description: "Success" - content: - application/json: - schema: - type: object - required: - - results - properties: - results: - type: array - items: - anyOf: - - type: object - properties: - order: - type: string - - type: object - properties: - error: - type: object - properties: - code: - type: number - message: - type: string diff --git a/experimental/internal/codegen/test/issues/issue_1710/doc.go b/experimental/internal/codegen/test/issues/issue_1710/doc.go deleted file mode 100644 index 3ce6436c35..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1710/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_1710 tests that fields are not lost in nested allOf oneOf structures. -// https://github.com/oapi-codegen/oapi-codegen/issues/1710 -package issue_1710 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go deleted file mode 100644 index 6efb31f3a5..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1710/output/types.gen.go +++ /dev/null @@ -1,212 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/BasePrompt -type BasePrompt struct { - Name string `json:"name" form:"name"` - Version int `json:"version" form:"version"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *BasePrompt) ApplyDefaults() { -} - -// #/components/schemas/TextPrompt -type TextPrompt struct { - Prompt string `json:"prompt" form:"prompt"` - Name string `json:"name" form:"name"` - Version int `json:"version" form:"version"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TextPrompt) ApplyDefaults() { -} - -// #/components/schemas/ChatMessage -type ChatMessage struct { - Role string `json:"role" form:"role"` - Content string `json:"content" form:"content"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ChatMessage) ApplyDefaults() { -} - -// #/components/schemas/ChatPrompt -type ChatPrompt struct { - Prompt []ChatMessage `json:"prompt" form:"prompt"` - Name string `json:"name" form:"name"` - Version int `json:"version" form:"version"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ChatPrompt) ApplyDefaults() { -} - -// #/components/schemas/ChatPrompt/properties/prompt -type ChatPromptPrompt = []ChatMessage - -// #/components/schemas/Prompt -type Prompt struct { - PromptOneOf0 *PromptOneOf0 - PromptOneOf1 *PromptOneOf1 -} - -func (u Prompt) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.PromptOneOf0 != nil { - count++ - data, err = json.Marshal(u.PromptOneOf0) - if err != nil { - return nil, err - } - } - if u.PromptOneOf1 != nil { - count++ - data, err = json.Marshal(u.PromptOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("Prompt: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *Prompt) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 PromptOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.PromptOneOf0 = &v0 - successCount++ - } - - var v1 PromptOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.PromptOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("Prompt: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *Prompt) ApplyDefaults() { - if u.PromptOneOf0 != nil { - u.PromptOneOf0.ApplyDefaults() - } - if u.PromptOneOf1 != nil { - u.PromptOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/Prompt/oneOf/0 -type PromptOneOf0 struct { - Type *string `json:"type,omitempty" form:"type,omitempty"` - Prompt []ChatMessage `json:"prompt" form:"prompt"` - Name string `json:"name" form:"name"` - Version int `json:"version" form:"version"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *PromptOneOf0) ApplyDefaults() { -} - -// #/components/schemas/Prompt/oneOf/0/allOf/0/properties/type -type PromptOneOf0AllOf0Type string - -const ( - PromptOneOf0AllOf0Type_chat PromptOneOf0AllOf0Type = "chat" -) - -// #/components/schemas/Prompt/oneOf/1 -type PromptOneOf1 struct { - Type *string `json:"type,omitempty" form:"type,omitempty"` - Prompt string `json:"prompt" form:"prompt"` - Name string `json:"name" form:"name"` - Version int `json:"version" form:"version"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *PromptOneOf1) ApplyDefaults() { -} - -// #/components/schemas/Prompt/oneOf/1/allOf/0/properties/type -type PromptOneOf1AllOf0Type string - -const ( - PromptOneOf1AllOf0Type_text PromptOneOf1AllOf0Type = "text" -) - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/9SUT4/TMBDF7/kUIwWpFzZpxQEpRzhxQMuhEmc3eYmNEtt4JvtHiO+O4qYbh2132RVC", - "oqfO68zzm5+b5PSJeQTt3u+2FbUGfUO9YyFjyYIFDam+v27JWVy3WU5axHNVlp0RPR6K2g2lU95c1a5B", - "B7suzOTN5WSe5VlOXzUsjWxstza/NaKPJ7ydlGMOJtZu7Bs6gHwAI9ygKbKc9hq08cENXjZz5FvFdMDk", - "O4UvMudhlTcVvSu2xTYztnVVRiRGelTJyrQHS0Z0g8DG2Yp2sd8r0VzRj59Z7QbvLKzwNM+1xqDiV6IP", - "ivElpjjWRHLvUZE7fEMts+SD8whiwKcmIqsGLNVpjCUY2z3Ip0SP+owVdAizHvB9NAHN0ncV/ZNydorK", - "Hnfyqsx+NXQh9bkwx8FZiLed/vomoK1ok5cL53KGXC58N3Hio1byGcyqwwvDB9c/D7x2VmBfs+Jkn5Sz", - "0UPmv8pbhaDuE9UIBk7b6EmmCcPNP7m09fLxEU+tztA4c+STvZcIrrg9Ui/8CZYP7DicG4s3rJX8Fu45", - "6CmTS9yXNf97QoK7lxBaXkt/TOhXAAAA//+WRkFKuQYAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go b/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go deleted file mode 100644 index 345ab353e9..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1710/output/types_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestPromptOneOfHasPromptField verifies that the 'prompt' field is not lost -// in nested allOf/oneOf structures. -// https://github.com/oapi-codegen/oapi-codegen/issues/1710 -func TestPromptOneOfHasPromptField(t *testing.T) { - // Test ChatPrompt variant (PromptOneOf0) - prompt is []ChatMessage - chatType := "chat" - chatPrompt := PromptOneOf0{ - Type: &chatType, - Prompt: []ChatMessage{ - {Role: "user", Content: "hello"}, - }, - } - - if chatPrompt.Type == nil || *chatPrompt.Type != "chat" { - t.Error("ChatPrompt variant should have Type='chat'") - } - if len(chatPrompt.Prompt) != 1 { - t.Errorf("ChatPrompt.Prompt should have 1 message, got %d", len(chatPrompt.Prompt)) - } - if chatPrompt.Prompt[0].Role != "user" { - t.Errorf("ChatPrompt.Prompt[0].Role = %q, want %q", chatPrompt.Prompt[0].Role, "user") - } - - // Test TextPrompt variant (PromptOneOf1) - prompt is string - textType := "text" - textPrompt := PromptOneOf1{ - Type: &textType, - Prompt: "Hello, world!", - } - - if textPrompt.Type == nil || *textPrompt.Type != "text" { - t.Error("TextPrompt variant should have Type='text'") - } - if textPrompt.Prompt != "Hello, world!" { - t.Errorf("TextPrompt.Prompt = %q, want %q", textPrompt.Prompt, "Hello, world!") - } -} - -func TestPromptJSONRoundTrip(t *testing.T) { - // Test chat prompt variant - chatType := "chat" - chatVariant := Prompt{ - PromptOneOf0: &PromptOneOf0{ - Type: &chatType, - Prompt: []ChatMessage{ - {Role: "user", Content: "test message"}, - }, - }, - } - - data, err := json.Marshal(chatVariant) - if err != nil { - t.Fatalf("Marshal chat variant failed: %v", err) - } - - var decoded Prompt - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal chat variant failed: %v", err) - } - - if decoded.PromptOneOf0 == nil { - t.Fatal("Expected PromptOneOf0 to be set after unmarshal") - } - if len(decoded.PromptOneOf0.Prompt) != 1 { - t.Errorf("Expected 1 message, got %d", len(decoded.PromptOneOf0.Prompt)) - } -} - -func TestTextPromptHasPromptField(t *testing.T) { - // Verify TextPrompt (from allOf) has the prompt field - tp := TextPrompt{ - Prompt: "my prompt", - Name: "test", - Version: 1, - } - - if tp.Prompt != "my prompt" { - t.Errorf("TextPrompt.Prompt = %q, want %q", tp.Prompt, "my prompt") - } -} - -func TestChatPromptHasPromptField(t *testing.T) { - // Verify ChatPrompt (from allOf) has the prompt field - cp := ChatPrompt{ - Prompt: []ChatMessage{ - {Role: "assistant", Content: "hello"}, - }, - Name: "test", - Version: 1, - } - - if len(cp.Prompt) != 1 { - t.Errorf("ChatPrompt.Prompt should have 1 message, got %d", len(cp.Prompt)) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_1710/spec.yaml b/experimental/internal/codegen/test/issues/issue_1710/spec.yaml deleted file mode 100644 index b1219e00d7..0000000000 --- a/experimental/internal/codegen/test/issues/issue_1710/spec.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# Issue 1710: field lost in nested allOf oneOf -# https://github.com/oapi-codegen/oapi-codegen/issues/1710 -# -# When using nested allOf with oneOf, all fields should be preserved. -# The 'prompt' field was being lost. -openapi: 3.0.0 -info: - title: Issue 1710 Test - version: 1.0.0 -paths: {} -components: - schemas: - BasePrompt: - type: object - properties: - name: - type: string - version: - type: integer - required: - - name - - version - TextPrompt: - type: object - properties: - prompt: - type: string - required: - - prompt - allOf: - - $ref: '#/components/schemas/BasePrompt' - ChatMessage: - type: object - properties: - role: - type: string - content: - type: string - required: - - role - - content - ChatPrompt: - type: object - properties: - prompt: - type: array - items: - $ref: '#/components/schemas/ChatMessage' - required: - - prompt - allOf: - - $ref: '#/components/schemas/BasePrompt' - Prompt: - oneOf: - - type: object - allOf: - - type: object - properties: - type: - type: string - enum: - - chat - - $ref: '#/components/schemas/ChatPrompt' - required: - - type - - type: object - allOf: - - type: object - properties: - type: - type: string - enum: - - text - - $ref: '#/components/schemas/TextPrompt' - required: - - type diff --git a/experimental/internal/codegen/test/issues/issue_193/doc.go b/experimental/internal/codegen/test/issues/issue_193/doc.go deleted file mode 100644 index dcf3fbff8c..0000000000 --- a/experimental/internal/codegen/test/issues/issue_193/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_193 tests allOf with additionalProperties merging. -// https://github.com/oapi-codegen/oapi-codegen/issues/193 -package issue_193 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go deleted file mode 100644 index 33a950f497..0000000000 --- a/experimental/internal/codegen/test/issues/issue_193/output/types.gen.go +++ /dev/null @@ -1,71 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Person -type Person struct { - Metadata string `json:"metadata" form:"metadata"` - Name *string `json:"name,omitempty" form:"name,omitempty"` - Age *float32 `json:"age,omitempty" form:"age,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Person) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/6yQvW7jQAyE+32KAVzbsuHK21151fkV1itK4kG73FtSFwRB3j2QHP8BMZAiHTn4SM5w", - "hd+qE2F32Hv8Gsc/HV7YBoS2ZWPJYTxWKVSNSZGo9px7t8JgVtQ3Tc82TKdNlNRIKLyO0lJP+bHh+YI2", - "u8PeSaEcCnvsN9vN1nHuxDvA2EbyMFKDxoFScMB/qsqSPXYLW4IN6vH27qKkIpmy6Tx75pcSOFJVyeca", - "CHOeSwOsECUlyeiYxlav+hr2WshDTn8p2lXGl0/wsDrRHVTp38SVWn+nzTsTWWiDhTu53LY8wBf0UcWn", - "LbU6P/2WoiwhoYUidxx/Ns4zjzkk+pa/5VL/hM1TOlF1HwEAAP//7z/Hg3YCAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_193/output/types_test.go b/experimental/internal/codegen/test/issues/issue_193/output/types_test.go deleted file mode 100644 index 301c97d923..0000000000 --- a/experimental/internal/codegen/test/issues/issue_193/output/types_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestAllOfWithAdditionalProperties verifies that allOf with additionalProperties: true -// merges fields correctly from multiple allOf members. -// https://github.com/oapi-codegen/oapi-codegen/issues/193 -func TestAllOfWithAdditionalProperties(t *testing.T) { - name := "John" - age := float32(30) - - person := Person{ - Metadata: "some-metadata", - Name: &name, - Age: &age, - } - - // All fields from both allOf members should be present - if person.Metadata != "some-metadata" { - t.Errorf("Metadata = %q, want %q", person.Metadata, "some-metadata") - } - if *person.Name != "John" { - t.Errorf("Name = %q, want %q", *person.Name, "John") - } - if *person.Age != 30 { - t.Errorf("Age = %v, want %v", *person.Age, 30) - } -} - -func TestPersonJSONRoundTrip(t *testing.T) { - name := "Jane" - age := float32(25) - original := Person{ - Metadata: "meta", - Name: &name, - Age: &age, - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded Person - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if decoded.Metadata != original.Metadata { - t.Errorf("Metadata mismatch: got %q, want %q", decoded.Metadata, original.Metadata) - } - if *decoded.Name != *original.Name { - t.Errorf("Name mismatch: got %q, want %q", *decoded.Name, *original.Name) - } - if *decoded.Age != *original.Age { - t.Errorf("Age mismatch: got %v, want %v", *decoded.Age, *original.Age) - } -} - -func TestMetadataIsRequired(t *testing.T) { - // Metadata is required (no omitempty), so empty struct should marshal with empty string - person := Person{} - data, err := json.Marshal(person) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - // Should contain "metadata" even if empty - expected := `{"metadata":""}` - if string(data) != expected { - t.Errorf("Marshal result = %s, want %s", string(data), expected) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_193/spec.yaml b/experimental/internal/codegen/test/issues/issue_193/spec.yaml deleted file mode 100644 index 375d227fb4..0000000000 --- a/experimental/internal/codegen/test/issues/issue_193/spec.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Issue 193: AllOf with additionalProperties merging -# https://github.com/oapi-codegen/oapi-codegen/issues/193 -openapi: 3.0.0 -info: - title: test schema - version: 1.0.0 -paths: {} -components: - schemas: - Person: - allOf: - # common fields - - type: object - additionalProperties: true - required: - - metadata - properties: - metadata: - type: string - # person specific fields - - type: object - additionalProperties: true - properties: - name: - type: string - age: - type: number diff --git a/experimental/internal/codegen/test/issues/issue_2102/doc.go b/experimental/internal/codegen/test/issues/issue_2102/doc.go deleted file mode 100644 index 753b091ce1..0000000000 --- a/experimental/internal/codegen/test/issues/issue_2102/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_2102 tests that properties defined at the same level as allOf are included. -// https://github.com/oapi-codegen/oapi-codegen/issues/2102 -package issue_2102 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go deleted file mode 100644 index 43d8ca049e..0000000000 --- a/experimental/internal/codegen/test/issues/issue_2102/output/types.gen.go +++ /dev/null @@ -1,82 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Foo -type Foo struct { - Foo string `json:"foo" form:"foo"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Foo) ApplyDefaults() { -} - -// #/components/schemas/Bar -type Bar struct { - Bar string `json:"bar" form:"bar"` - Foo string `json:"foo" form:"foo"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Bar) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/3xSwY6bMBC98xVPS6VcmpBNbxz3sFJPvVTqNQYP2CvwuJ5hq/x9BSQ16UbLBfzmzXsz", - "z5T4LjIRTs/HUw0zDD86/PHqEBNHSupJYBRiRsJA7zRgf1dKBN8HTmSLEk41Sl1VvVc3NYeWx4pN9PuW", - "LfUU7g9+9pVqNi7KosQvRwEG0joaDZwRNKwO5+x2hgkW52XI8zyVOtpM9rUoF2QznqXOB7KwPlGrwwUc", - "1qbVRBxPg0VDGCn1ZJfNP6p0iccFW+NJ1FGi0JIcCo4UTPQ1vh2Oh2PhQ8d1AajXgepNtPhJogXwTkk8", - "hxrPCz8adTI3VI1J8xvoSdcPQKZxNOlSozHpCiWSyEFIbhzg6XQ8PuUjYEna5KMuPrl1floOSkG3bMDE", - "OPjWzPzqTTjcV3EN638U+JKoq7Erq5bHyIGCSrVypXoxaVdkfG6+lladV+aboF4i1eDmjVr9t+XvySey", - "2XOPjvl6yjeT613Wy5qiyYd+gV9u8T70e6TY5I6Hilj/hu2InwXyyrzbUD9uuOLzdf0NAAD//90rMTaT", - "AwAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go b/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go deleted file mode 100644 index b4916b2c33..0000000000 --- a/experimental/internal/codegen/test/issues/issue_2102/output/types_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestBarHasBothProperties verifies that Bar has both foo and bar properties. -// Issue 2102: When a schema has both properties and allOf at the same level, -// the properties were being ignored. -func TestBarHasBothProperties(t *testing.T) { - // Bar should have both foo (from allOf ref to Foo) and bar (from direct properties) - bar := Bar{ - Foo: "test-foo", - Bar: "test-bar", - } - - // Should be able to marshal/unmarshal - data, err := json.Marshal(bar) - if err != nil { - t.Fatalf("Failed to marshal Bar: %v", err) - } - - var unmarshaled Bar - if err := json.Unmarshal(data, &unmarshaled); err != nil { - t.Fatalf("Failed to unmarshal Bar: %v", err) - } - - if unmarshaled.Foo != "test-foo" { - t.Errorf("Expected Foo to be 'test-foo', got %q", unmarshaled.Foo) - } - if unmarshaled.Bar != "test-bar" { - t.Errorf("Expected Bar to be 'test-bar', got %q", unmarshaled.Bar) - } -} - -// TestBarRequiredFields verifies that bar is required (from allOf member's required array). -func TestBarRequiredFields(t *testing.T) { - // Both foo and bar should be required (no omitempty), so an empty struct - // should marshal with empty string values - bar := Bar{} - data, err := json.Marshal(bar) - if err != nil { - t.Fatalf("Failed to marshal empty Bar: %v", err) - } - - // Both fields should be present in JSON - expected := `{"bar":"","foo":""}` - if string(data) != expected { - t.Errorf("Expected %s, got %s", expected, string(data)) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_2102/spec.yaml b/experimental/internal/codegen/test/issues/issue_2102/spec.yaml deleted file mode 100644 index cbafb5a6d3..0000000000 --- a/experimental/internal/codegen/test/issues/issue_2102/spec.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Issue 2102: allOf with properties at same level - properties are ignored -# https://github.com/oapi-codegen/oapi-codegen/issues/2102 -# -# When a schema has both `properties` and `allOf` at the same level, -# the properties defined directly on the schema should be merged with -# the properties from the allOf references. -openapi: 3.0.0 -info: - title: Issue 2102 Test - version: 1.0.0 -paths: - /bar: - get: - summary: bar - responses: - "200": - description: bar - content: - application/json: - schema: - $ref: '#/components/schemas/Bar' -components: - schemas: - Foo: - type: object - required: - - foo - properties: - foo: - type: string - Bar: - type: object - properties: - bar: - type: string - allOf: - - $ref: '#/components/schemas/Foo' - - required: - - bar diff --git a/experimental/internal/codegen/test/issues/issue_312/doc.go b/experimental/internal/codegen/test/issues/issue_312/doc.go deleted file mode 100644 index 0f29af76ad..0000000000 --- a/experimental/internal/codegen/test/issues/issue_312/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Package issue_312 tests proper escaping of paths with special characters. -// https://github.com/oapi-codegen/oapi-codegen/issues/312 -// This tests paths with colons like /pets:validate -package issue_312 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go deleted file mode 100644 index f5f81dbf6e..0000000000 --- a/experimental/internal/codegen/test/issues/issue_312/output/types.gen.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Pet -type Pet struct { - Name string `json:"name" form:"name"` // The name of the pet. -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Pet) ApplyDefaults() { -} - -// #/components/schemas/PetNames -type PetNames struct { - Names []string `json:"names" form:"names"` // The names of the pets. -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *PetNames) ApplyDefaults() { -} - -// #/components/schemas/Error -type Error struct { - Code int32 `json:"code" form:"code"` // Error code - Message string `json:"message" form:"message"` // Error message -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Error) ApplyDefaults() { -} - -// #/paths//pets:validate/post/responses/200/content/application/json/schema -type ValidatePetsJSONResponse = []Pet - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/8SVTW/bPAzH7/oURPMAOdVOk5uOzzAMvQw5DLurMm2rtSVNpLsFw777IDmu7TpxsQ3D", - "bjEpkb8/X5QN3BN1CIe7vYSj4hqQtPLGVmIDNbMnmeeV4bp7yLRrc6e8udWuwArt/MPEOJQf7vZiA+9q", - "1E8EPjiP4SUkuBK84prgq+EayKM2qgFdq6A0YyBozBOCdo2zJJxHq7yRcHPIdtnuRhhbOikAnjGQcVbC", - "XbQLADbcoByVACOxACiQdDCe0+E1pKBajPlFoos5co9M8lk1plCM0QLgHXH/C4C6tlXhJOHz+QjEC2fn", - "LO+lAxFBRfd9IWFIchz9Ab90SPy/K05Dwt5oAhYSOHT4YtbOMloezwEo7xujU4L8kZyd+gBI19iquQ3g", - "v4ClhO0m1671zqJlyvuTlB+RP6oWafuCR95ZQhqDbPe73XYac1aDJHFagCvgb6Ffgwfgk0cJKgR1WvgM", - "Y0vLK29q3opRTKm6hq/q6yx+86gZC8AQXPhbKteA38fE22F08+8e+b740ceocDm4H5BjR6Ayz2jBFGjZ", - "lAZDdmlGK+Qj8tkz7stIeAtWtSghZZ1wGyvTyk9MV+b4suq+r8Qhvkh/On3/oi1pjkZ7vHx29XGOY2t6", - "re7hETWLV7V6VeihE+kxYzOtReqDWK3gokKfakz34mvIdXqqMjHgpdX/DUZ6A5KWlK/39yIkTSgpE6t7", - "PhOfPGlN5Ap6/D+bfLZIpKq1gscLSynGMlY4fQlKF1rFyXPYXxOZ8OYMZ4Jf7WkfacD/GQAA//+iio0s", - "6AcAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_312/output/types_test.go b/experimental/internal/codegen/test/issues/issue_312/output/types_test.go deleted file mode 100644 index 3a2818f642..0000000000 --- a/experimental/internal/codegen/test/issues/issue_312/output/types_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestPathWithColon verifies that paths with colons (like /pets:validate) generate properly. -// https://github.com/oapi-codegen/oapi-codegen/issues/312 -func TestPathWithColonGeneratesTypes(t *testing.T) { - // The path /pets:validate should generate a ValidatePetsJSONResponse type - response := ValidatePetsJSONResponse{ - {Name: "Fluffy"}, - {Name: "Spot"}, - } - - if len(response) != 2 { - t.Errorf("response length = %d, want 2", len(response)) - } - if response[0].Name != "Fluffy" { - t.Errorf("response[0].Name = %q, want %q", response[0].Name, "Fluffy") - } -} - -func TestPetSchema(t *testing.T) { - pet := Pet{ - Name: "Max", - } - - data, err := json.Marshal(pet) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - expected := `{"name":"Max"}` - if string(data) != expected { - t.Errorf("Marshal result = %s, want %s", string(data), expected) - } -} - -func TestPetNamesSchema(t *testing.T) { - petNames := PetNames{ - Names: []string{"Fluffy", "Spot", "Max"}, - } - - data, err := json.Marshal(petNames) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded PetNames - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if len(decoded.Names) != 3 { - t.Errorf("Names length = %d, want 3", len(decoded.Names)) - } -} - -func TestErrorSchema(t *testing.T) { - err := Error{ - Code: 404, - Message: "Not Found", - } - - data, _ := json.Marshal(err) - expected := `{"code":404,"message":"Not Found"}` - if string(data) != expected { - t.Errorf("Marshal result = %s, want %s", string(data), expected) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_312/spec.yaml b/experimental/internal/codegen/test/issues/issue_312/spec.yaml deleted file mode 100644 index fa458ec41f..0000000000 --- a/experimental/internal/codegen/test/issues/issue_312/spec.yaml +++ /dev/null @@ -1,86 +0,0 @@ -# Issue 312: Path escaping -# https://github.com/oapi-codegen/oapi-codegen/issues/312 -# Checks proper escaping of paths with special characters like colons -openapi: "3.0.0" -info: - version: 1.0.0 - title: Issue 312 test - description: Checks proper escaping of parameters -paths: - /pets:validate: - post: - summary: Validate pets - description: Validate pets - operationId: validatePets - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/PetNames' - responses: - '200': - description: valid pets - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /pets/{petId}: - get: - summary: Get pet given identifier. - operationId: getPet - parameters: - - name: petId - in: path - required: true - schema: - type: string - responses: - '200': - description: valid pet - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' -components: - schemas: - Pet: - type: object - required: - - name - properties: - name: - type: string - description: The name of the pet. - - PetNames: - type: object - required: - - names - properties: - names: - type: array - description: The names of the pets. - items: - type: string - - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - description: Error code - message: - type: string - description: Error message diff --git a/experimental/internal/codegen/test/issues/issue_502/doc.go b/experimental/internal/codegen/test/issues/issue_502/doc.go deleted file mode 100644 index 992436f9e7..0000000000 --- a/experimental/internal/codegen/test/issues/issue_502/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_502 tests that anyOf with only one ref generates the referenced type. -// https://github.com/oapi-codegen/oapi-codegen/issues/502 -package issue_502 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go deleted file mode 100644 index cda70dd5ea..0000000000 --- a/experimental/internal/codegen/test/issues/issue_502/output/types.gen.go +++ /dev/null @@ -1,228 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/OptionalClaims -type OptionalClaims struct { - IDToken *string `json:"idToken,omitempty" form:"idToken,omitempty"` - AccessToken *string `json:"accessToken,omitempty" form:"accessToken,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *OptionalClaims) ApplyDefaults() { -} - -// #/components/schemas/Application -type Application struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` - OptionalClaims Nullable[ApplicationOptionalClaims] `json:"optionalClaims,omitempty" form:"optionalClaims,omitempty"` // Optional claims configuration -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Application) ApplyDefaults() { -} - -// #/components/schemas/Application/properties/optionalClaims -// Optional claims configuration -type ApplicationOptionalClaims struct { - OptionalClaims *OptionalClaims -} - -func (u ApplicationOptionalClaims) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.OptionalClaims != nil { - data, err := json.Marshal(u.OptionalClaims) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *ApplicationOptionalClaims) UnmarshalJSON(data []byte) error { - var v0 OptionalClaims - if err := json.Unmarshal(data, &v0); err == nil { - u.OptionalClaims = &v0 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ApplicationOptionalClaims) ApplyDefaults() { - if u.OptionalClaims != nil { - u.OptionalClaims.ApplyDefaults() - } -} - -// Nullable is a generic type that can distinguish between: -// - Field not provided (unspecified) -// - Field explicitly set to null -// - Field has a value -// -// This is implemented as a map[bool]T where: -// - Empty map: unspecified -// - map[false]T: explicitly null -// - map[true]T: has a value -type Nullable[T any] map[bool]T - -// NewNullableWithValue creates a Nullable with the given value. -func NewNullableWithValue[T any](value T) Nullable[T] { - return Nullable[T]{true: value} -} - -// NewNullNullable creates a Nullable that is explicitly null. -func NewNullNullable[T any]() Nullable[T] { - return Nullable[T]{false: *new(T)} -} - -// Get returns the value if set, or an error if null or unspecified. -func (n Nullable[T]) Get() (T, error) { - if v, ok := n[true]; ok { - return v, nil - } - var zero T - if n.IsNull() { - return zero, ErrNullableIsNull - } - return zero, ErrNullableNotSpecified -} - -// MustGet returns the value or panics if null or unspecified. -func (n Nullable[T]) MustGet() T { - v, err := n.Get() - if err != nil { - panic(err) - } - return v -} - -// Set assigns a value. -func (n *Nullable[T]) Set(value T) { - *n = Nullable[T]{true: value} -} - -// SetNull marks the field as explicitly null. -func (n *Nullable[T]) SetNull() { - *n = Nullable[T]{false: *new(T)} -} - -// SetUnspecified clears the field (as if it was never set). -func (n *Nullable[T]) SetUnspecified() { - *n = nil -} - -// IsNull returns true if the field is explicitly null. -func (n Nullable[T]) IsNull() bool { - if n == nil { - return false - } - _, ok := n[false] - return ok -} - -// IsSpecified returns true if the field was provided (either null or a value). -func (n Nullable[T]) IsSpecified() bool { - return len(n) > 0 -} - -// MarshalJSON implements json.Marshaler. -func (n Nullable[T]) MarshalJSON() ([]byte, error) { - if n.IsNull() { - return []byte("null"), nil - } - if v, ok := n[true]; ok { - return json.Marshal(v) - } - // Unspecified - this shouldn't be called if omitempty is used correctly - return []byte("null"), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (n *Nullable[T]) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - n.SetNull() - return nil - } - var v T - if err := json.Unmarshal(data, &v); err != nil { - return err - } - n.Set(v) - return nil -} - -// ErrNullableIsNull is returned when trying to get a value from a null Nullable. -var ErrNullableIsNull = errors.New("nullable value is null") - -// ErrNullableNotSpecified is returned when trying to get a value from an unspecified Nullable. -var ErrNullableNotSpecified = errors.New("nullable value is not specified") - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/5SRQWvcMBSE7/oVAy7kkqy3KbnoVnrqaS+BnrXys/1a+T0hPbcsIf+92NnueqEQcrNH", - "M8ynUYPvtc6Ep/2jR5DToW9DSocef9hGqKQTVAiFetgpEwYSKsGogsWo9CHSy6trMJrl6tt2YBvn4y7q", - "1GrI/BC1o4Hk9oeXyto+7R9d4xr8GEneuqEFb/VjqDftVEgi3YMNddQ5dRcS18DGjadbQe8halvGndNM", - "EjJ7fNntd3vH0qt3gLEl8tcZ8EzVHPCbSmUVj8+rPQcbq8fLq4s6ZRUSq0u8xpGmsH4Ch2ysEtK3FHg6", - "a1h5PPT4k6KdpVw0UzGmiwng7ll/kVyFf8lqhWW4yCFGqvV979ecE8ewEH2QRMJE72Lof++6Ai5PuRWA", - "B3wq1HvcNe11vva8XXs7290m2VGNhddjf1kXcfUhqvQ8zGW94iYkc0rhuDyqlZnc3wAAAP//6uhqZ+MC", - "AAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_502/output/types_test.go b/experimental/internal/codegen/test/issues/issue_502/output/types_test.go deleted file mode 100644 index c0f7f6bb71..0000000000 --- a/experimental/internal/codegen/test/issues/issue_502/output/types_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestAnyOfWithSingleRef verifies that anyOf with a single $ref generates -// correct types that can be used. -// https://github.com/oapi-codegen/oapi-codegen/issues/502 -func TestAnyOfWithSingleRef(t *testing.T) { - // OptionalClaims should be properly generated - claims := OptionalClaims{ - IDToken: ptrTo("id-token-value"), - AccessToken: ptrTo("access-token-value"), - } - - if *claims.IDToken != "id-token-value" { - t.Errorf("IDToken = %q, want %q", *claims.IDToken, "id-token-value") - } - if *claims.AccessToken != "access-token-value" { - t.Errorf("AccessToken = %q, want %q", *claims.AccessToken, "access-token-value") - } -} - -func TestApplicationWithAnyOfProperty(t *testing.T) { - // Application.OptionalClaims is an anyOf with a single ref + nullable: true - // It should be Nullable[ApplicationOptionalClaims] - app := Application{ - Name: ptrTo("my-app"), - OptionalClaims: NewNullableWithValue(ApplicationOptionalClaims{ - OptionalClaims: &OptionalClaims{ - IDToken: ptrTo("token"), - }, - }), - } - - if *app.Name != "my-app" { - t.Errorf("Name = %q, want %q", *app.Name, "my-app") - } - if !app.OptionalClaims.IsSpecified() { - t.Fatal("OptionalClaims should be specified") - } - optClaims := app.OptionalClaims.MustGet() - if optClaims.OptionalClaims == nil { - t.Fatal("OptionalClaims.OptionalClaims should not be nil") - } - if *optClaims.OptionalClaims.IDToken != "token" { - t.Errorf("IDToken = %q, want %q", *optClaims.OptionalClaims.IDToken, "token") - } -} - -func TestApplicationJSONRoundTrip(t *testing.T) { - original := Application{ - Name: ptrTo("test-app"), - OptionalClaims: NewNullableWithValue(ApplicationOptionalClaims{ - OptionalClaims: &OptionalClaims{ - IDToken: ptrTo("id"), - AccessToken: ptrTo("access"), - }, - }), - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded Application - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if *decoded.Name != *original.Name { - t.Errorf("Name mismatch: got %q, want %q", *decoded.Name, *original.Name) - } - if !decoded.OptionalClaims.IsSpecified() { - t.Fatal("OptionalClaims should be specified after round trip") - } - optClaims := decoded.OptionalClaims.MustGet() - if optClaims.OptionalClaims == nil { - t.Fatal("OptionalClaims.OptionalClaims should not be nil after round trip") - } -} - -func TestApplicationNullOptionalClaims(t *testing.T) { - // Test with explicitly null optional claims - app := Application{ - Name: ptrTo("null-test-app"), - OptionalClaims: NewNullNullable[ApplicationOptionalClaims](), - } - - if !app.OptionalClaims.IsNull() { - t.Error("OptionalClaims should be null") - } - - // Should marshal as null - data, err := json.Marshal(app) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - t.Logf("Marshaled with null optionalClaims: %s", string(data)) -} - -func ptrTo[T any](v T) *T { - return &v -} diff --git a/experimental/internal/codegen/test/issues/issue_502/spec.yaml b/experimental/internal/codegen/test/issues/issue_502/spec.yaml deleted file mode 100644 index 04e5a324e8..0000000000 --- a/experimental/internal/codegen/test/issues/issue_502/spec.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Issue 502: anyOf/allOf with only one ref type generates interface{} -# https://github.com/oapi-codegen/oapi-codegen/issues/502 -# -# When anyOf or allOf has only one reference, it should generate -# the referenced type, not interface{}. -openapi: 3.0.0 -info: - title: Issue 502 Test - version: 1.0.0 -paths: {} -components: - schemas: - OptionalClaims: - type: object - properties: - idToken: - type: string - accessToken: - type: string - Application: - type: object - properties: - name: - type: string - optionalClaims: - anyOf: - - $ref: '#/components/schemas/OptionalClaims' - description: Optional claims configuration - nullable: true diff --git a/experimental/internal/codegen/test/issues/issue_52/doc.go b/experimental/internal/codegen/test/issues/issue_52/doc.go deleted file mode 100644 index f4646cbdb6..0000000000 --- a/experimental/internal/codegen/test/issues/issue_52/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_52 tests that recursive types are handled properly. -// https://github.com/oapi-codegen/oapi-codegen/issues/52 -package issue_52 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go deleted file mode 100644 index 72354dfa93..0000000000 --- a/experimental/internal/codegen/test/issues/issue_52/output/types.gen.go +++ /dev/null @@ -1,87 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Document -type Document struct { - Fields map[string]any `json:"fields,omitempty" form:"fields,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Document) ApplyDefaults() { -} - -// #/components/schemas/Document/properties/fields -type DocumentFields = map[string]any - -// #/components/schemas/Value -type Value struct { - StringValue *string `json:"stringValue,omitempty" form:"stringValue,omitempty"` - ArrayValue *ArrayValue `json:"arrayValue,omitempty" form:"arrayValue,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Value) ApplyDefaults() { -} - -// #/components/schemas/ArrayValue -type ArrayValue = []Value - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/5xQTWvcMBC961c8sgWdarlbctEtUCihlJYeelfkWVupLQnNOHShP77Y3g/vJvQjOknz", - "3rwPbXDPPBJutxbfyI+FwxNB9pkYnYtNH2KrNuhEMltj2iDd+FD5NJjkcnjrU0MtxctHmBTZ3G7VRm3w", - "2f0g8FgI0jlBuTJxhRYjapBLylT6vUqZosvB4n1VV1sV4i5ZBTxR4ZCiha6runqnFSBBerKgn27IPSmg", - "IfYlZJl5vxSAVyXITjqePM1B2s5SLclyASaim2zum5P/R5IDWohzikx8pAN6W9f6/LyKevPl080K8ykK", - "RVnTAe1y7oOfXc0jp6gvcYB9R4O7ngJvCu0s9Mb4NOQUKQqbhcvmQ/LjQFG0OoOTwgFfxI6ko/T0dRbp", - "4ZH8sfLydxLWnXeB+obXeV5YnI5rmjDVcv3XF2T+VuG760fSM32+/mdKlhJie7F53l7A09iV4vbPqH8K", - "d3faWBLePVNYjGblwyQIDauA/9D9dwAAAP//+4PlsMkDAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_52/output/types_test.go b/experimental/internal/codegen/test/issues/issue_52/output/types_test.go deleted file mode 100644 index 7bb4f39267..0000000000 --- a/experimental/internal/codegen/test/issues/issue_52/output/types_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestRecursiveTypes verifies that recursive type definitions work correctly. -// https://github.com/oapi-codegen/oapi-codegen/issues/52 -func TestRecursiveTypes(t *testing.T) { - // Value references ArrayValue which is []Value - recursive - str := "test" - val := Value{ - StringValue: &str, - ArrayValue: &ArrayValue{ - {StringValue: &str}, - }, - } - - if *val.StringValue != "test" { - t.Errorf("StringValue = %q, want %q", *val.StringValue, "test") - } - if len(*val.ArrayValue) != 1 { - t.Errorf("ArrayValue length = %d, want 1", len(*val.ArrayValue)) - } -} - -func TestRecursiveJSONRoundTrip(t *testing.T) { - str := "test" - nested := "nested" - original := Value{ - StringValue: &str, - ArrayValue: &ArrayValue{ - {StringValue: &nested}, - }, - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded Value - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if *decoded.StringValue != *original.StringValue { - t.Errorf("StringValue mismatch: got %q, want %q", *decoded.StringValue, *original.StringValue) - } -} - -func TestDocumentWithRecursiveFields(t *testing.T) { - // Document.Fields is map[string]any (due to additionalProperties: $ref Value) - doc := Document{ - Fields: map[string]any{ - "key1": "value1", - }, - } - - if doc.Fields["key1"] != "value1" { - t.Errorf("Fields[key1] = %v, want %q", doc.Fields["key1"], "value1") - } -} diff --git a/experimental/internal/codegen/test/issues/issue_52/spec.yaml b/experimental/internal/codegen/test/issues/issue_52/spec.yaml deleted file mode 100644 index a29ee7a7be..0000000000 --- a/experimental/internal/codegen/test/issues/issue_52/spec.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Issue 52: Recursive types handling -# https://github.com/oapi-codegen/oapi-codegen/issues/52 -# -# Make sure that recursive types are handled properly -openapi: 3.0.2 -info: - version: '0.0.1' - title: example - description: | - Make sure that recursive types are handled properly -paths: - /example: - get: - operationId: exampleGet - responses: - '200': - description: "OK" - content: - 'application/json': - schema: - $ref: '#/components/schemas/Document' -components: - schemas: - Document: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/components/schemas/Value' - Value: - type: object - properties: - stringValue: - type: string - arrayValue: - $ref: '#/components/schemas/ArrayValue' - ArrayValue: - type: array - items: - $ref: '#/components/schemas/Value' diff --git a/experimental/internal/codegen/test/issues/issue_579/doc.go b/experimental/internal/codegen/test/issues/issue_579/doc.go deleted file mode 100644 index 10d90fa7f5..0000000000 --- a/experimental/internal/codegen/test/issues/issue_579/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_579 tests aliased types with date format. -// https://github.com/oapi-codegen/oapi-codegen/issues/579 -package issue_579 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go deleted file mode 100644 index 071c05c0f4..0000000000 --- a/experimental/internal/codegen/test/issues/issue_579/output/types.gen.go +++ /dev/null @@ -1,110 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" - "time" -) - -// #/components/schemas/Pet -type Pet struct { - Born *any `json:"born,omitempty" form:"born,omitempty"` - BornAt *Date `json:"born_at,omitempty" form:"born_at,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Pet) ApplyDefaults() { -} - -const DateFormat = "2006-01-02" - -type Date struct { - time.Time -} - -func (d Date) MarshalJSON() ([]byte, error) { - return json.Marshal(d.Format(DateFormat)) -} - -func (d *Date) UnmarshalJSON(data []byte) error { - var dateStr string - err := json.Unmarshal(data, &dateStr) - if err != nil { - return err - } - parsed, err := time.Parse(DateFormat, dateStr) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -func (d Date) String() string { - return d.Format(DateFormat) -} - -func (d *Date) UnmarshalText(data []byte) error { - parsed, err := time.Parse(DateFormat, string(data)) - if err != nil { - return err - } - d.Time = parsed - return nil -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/2SSz86bMBDE7zzFiPTamLaKovhWqZfc8gaVYzbgCryWd9M/b18Z+ET8fZzY0c74N+AD", - "riJPwul8sfg+BSfUQ/8lEvwJOqJ3Snhwnp02B4yqSawxQ9DxeT96ng27FD577mmgWA+hBIs5nS8NJ4ou", - "BYv227E7dm0T4oNtA/ymLIGjxZeiN4AGncjuUFASbZLTUcq+SZPzNPLUUy4zMJCuLwAnyk4Dx2tvi37b", - "d7eNTJI4CsmbBfjadfsA9CQ+h6QLVPoQUB7PUSnqqwtQ+qsFLsRaB8SPNLv3KpaPbCGaQxwaz3PiSFEX", - "stWyQd72gquF77/I6yalXFpreK1051xRfMr0sGgPZj/FbEeY7Zf/cEptFfDTVQ0r2l1eb4Zdrskiv+TV", - "1JW1sv0PAAD//3OxuKeDAgAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_579/output/types_test.go b/experimental/internal/codegen/test/issues/issue_579/output/types_test.go deleted file mode 100644 index 895928b075..0000000000 --- a/experimental/internal/codegen/test/issues/issue_579/output/types_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" - "time" -) - -// TestAliasedDateType verifies that date format types work correctly. -// https://github.com/oapi-codegen/oapi-codegen/issues/579 -func TestDateType(t *testing.T) { - // Direct date type should use Date - date := Date{Time: time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)} - - data, err := json.Marshal(date) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - if string(data) != `"2024-01-15"` { - t.Errorf("Marshal result = %s, want %q", string(data), "2024-01-15") - } - - var decoded Date - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if !decoded.Equal(date.Time) { - t.Errorf("Unmarshal result = %v, want %v", decoded.Time, date.Time) - } -} - -func TestPetWithDateFields(t *testing.T) { - // Pet has born_at as *Date (direct format: date) - date := Date{Time: time.Date(2020, 6, 15, 0, 0, 0, 0, time.UTC)} - pet := Pet{ - BornAt: &date, - } - - if pet.BornAt == nil { - t.Fatal("BornAt should not be nil") - } - if pet.BornAt.String() != "2020-06-15" { - t.Errorf("BornAt = %q, want %q", pet.BornAt.String(), "2020-06-15") - } -} - -// Note: The current implementation generates Born as *any instead of the ideal -// AliasedDate type. This is a known limitation with $ref to type aliases. -func TestPetBornFieldExists(t *testing.T) { - // Just verify the field exists and can hold a value - pet := Pet{ - Born: ptrTo[any]("2020-06-15"), - } - - if pet.Born == nil { - t.Fatal("Born should not be nil") - } -} - -func ptrTo[T any](v T) *T { - return &v -} diff --git a/experimental/internal/codegen/test/issues/issue_579/spec.yaml b/experimental/internal/codegen/test/issues/issue_579/spec.yaml deleted file mode 100644 index 8baf490045..0000000000 --- a/experimental/internal/codegen/test/issues/issue_579/spec.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Issue 579: Aliased types with date format -# https://github.com/oapi-codegen/oapi-codegen/issues/579 -openapi: "3.0.0" -info: - version: 1.0.0 - title: Issue 579 test -paths: - /placeholder: - get: - operationId: getPlaceholder - responses: - 200: - description: placeholder - content: - text/plain: - schema: - type: string -components: - schemas: - Pet: - type: object - properties: - born: - $ref: "#/components/schemas/AliasedDate" - born_at: - type: string - format: date - AliasedDate: - type: string - format: date diff --git a/experimental/internal/codegen/test/issues/issue_697/doc.go b/experimental/internal/codegen/test/issues/issue_697/doc.go deleted file mode 100644 index 3b3d314ae0..0000000000 --- a/experimental/internal/codegen/test/issues/issue_697/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_697 tests that properties alongside allOf are included. -// https://github.com/oapi-codegen/oapi-codegen/issues/697 -package issue_697 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go deleted file mode 100644 index 1a342a9e92..0000000000 --- a/experimental/internal/codegen/test/issues/issue_697/output/types.gen.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/YBase -type YBase struct { - BaseField *string `json:"baseField,omitempty" form:"baseField,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *YBase) ApplyDefaults() { -} - -// #/components/schemas/X -type X struct { - A *string `json:"a,omitempty" form:"a,omitempty"` - B *int `json:"b,omitempty" form:"b,omitempty"` - BaseField *string `json:"baseField,omitempty" form:"baseField,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *X) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/3yQwWrcMBCG73qKH1zIpbE3KSRExx4KPbWHQNvj2Jq1psiS0MwGSum7lyhZ3NKyt/Hv", - "bzTfzICPqifG3cO9x+dWKjcTVmSmBkrp0xHUGLLm0ji4AdGsqp+mVSye5nEp21SoyvVSAq+c//6Q57d1", - "unu4d4Mb8CVyBkGXyBshkmIuFs9jckDdBchgkaG0MRI/cXrrhp78wWgspxQwMyQv6RQ4QHKHVs7cyDjA", - "flQe3YDHKApRqGySqMEKuh1ubw63oyuVM1XxeDcexoOTfCzeASaW2O83wiOrOeCJm0rJHjcdr2RRPX7+", - "ckvZasmcTZ/bXzbtJfDtPSm/lOhaHmX+zou9RvtiZwiYSfmDcAp7dO5Va5LXHn89/+2X3NFrvGl89Lga", - "pt1repWaus/VheF0cWjX+5eQbLxy+9+avwMAAP//FjslWWwCAAA=", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_697/output/types_test.go b/experimental/internal/codegen/test/issues/issue_697/output/types_test.go deleted file mode 100644 index f3d5263a93..0000000000 --- a/experimental/internal/codegen/test/issues/issue_697/output/types_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestXHasAllFields verifies that schema X has properties from both its own -// definition AND from the allOf reference to YBase. -// https://github.com/oapi-codegen/oapi-codegen/issues/697 -func TestXHasAllFields(t *testing.T) { - a := "a-value" - b := 42 - baseField := "base-value" - - x := X{ - A: &a, - B: &b, - BaseField: &baseField, - } - - // Verify all fields are accessible - if *x.A != "a-value" { - t.Errorf("X.A = %q, want %q", *x.A, "a-value") - } - if *x.B != 42 { - t.Errorf("X.B = %d, want %d", *x.B, 42) - } - if *x.BaseField != "base-value" { - t.Errorf("X.BaseField = %q, want %q", *x.BaseField, "base-value") - } -} - -func TestXJSONRoundTrip(t *testing.T) { - a := "a-value" - b := 42 - baseField := "base-value" - - original := X{ - A: &a, - B: &b, - BaseField: &baseField, - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded X - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if *decoded.A != *original.A || *decoded.B != *original.B || *decoded.BaseField != *original.BaseField { - t.Errorf("Round trip failed: got %+v, want %+v", decoded, original) - } -} diff --git a/experimental/internal/codegen/test/issues/issue_697/spec.yaml b/experimental/internal/codegen/test/issues/issue_697/spec.yaml deleted file mode 100644 index 314044fc9b..0000000000 --- a/experimental/internal/codegen/test/issues/issue_697/spec.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Issue 697: Properties near allOf are ignored -# https://github.com/oapi-codegen/oapi-codegen/issues/697 -# -# When a schema has both allOf and properties at the same level, -# the properties should be included in the generated type. -# This is similar to issue 2102. -openapi: 3.0.0 -info: - title: Issue 697 Test - version: 1.0.0 -paths: {} -components: - schemas: - YBase: - type: object - properties: - baseField: - type: string - X: - allOf: - - $ref: '#/components/schemas/YBase' - properties: - a: - type: string - b: - type: integer - type: object diff --git a/experimental/internal/codegen/test/issues/issue_775/doc.go b/experimental/internal/codegen/test/issues/issue_775/doc.go deleted file mode 100644 index f97f08fec2..0000000000 --- a/experimental/internal/codegen/test/issues/issue_775/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_775 tests that allOf with format specification works correctly. -// https://github.com/oapi-codegen/oapi-codegen/issues/775 -package issue_775 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go deleted file mode 100644 index 1cd65cb493..0000000000 --- a/experimental/internal/codegen/test/issues/issue_775/output/types.gen.go +++ /dev/null @@ -1,86 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/TestObject -type TestObject struct { - UUIDProperty *TestObjectUUIDProperty `json:"uuidProperty,omitempty" form:"uuidProperty,omitempty"` - DateProperty *TestObjectDateProperty `json:"dateProperty,omitempty" form:"dateProperty,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestObject) ApplyDefaults() { -} - -// #/components/schemas/TestObject/properties/uuidProperty -type TestObjectUUIDProperty struct { -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestObjectUUIDProperty) ApplyDefaults() { -} - -// #/components/schemas/TestObject/properties/dateProperty -type TestObjectDateProperty struct { -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *TestObjectDateProperty) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/6xQQW7bMBC88xUD61hYclEYAviDntxD+wBKWkvbSFyCu4phBPl7IFmOnXtunOHM7OwW", - "+K06E+r66BHG8XTGD5wlT8GQAyspdm2IiGKYKPcEjq1MKRg3I21K3YFyluwKDGZJfVX1bMPclK1MlYTE", - "+1Y66il+BbyM1qquj65wBf4px34rYYLQdQj3LgtGE5Rg10TQQeaxw0XyCy5sg8x2q6Clk0QxJPb4VR7K", - "g+N4Fu8AYxvJP9bFX1JzwCtlZYkeP1d5Cjaox9u7W9aUSNF0sWs70BTWJ1brqflPrd0w1lYesnIblbIk", - "ysakdxEwz9z9ufHXB3u3q2WO/RO93uJZB+y3i/g16/OrC0bfFbxkuY8AAAD//xKKQGYZAgAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_775/output/types_test.go b/experimental/internal/codegen/test/issues/issue_775/output/types_test.go deleted file mode 100644 index c2efe59909..0000000000 --- a/experimental/internal/codegen/test/issues/issue_775/output/types_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package output - -import ( - "testing" -) - -// TestAllOfWithFormatCompiles verifies that using allOf to add format -// specifications doesn't cause generation errors. -// https://github.com/oapi-codegen/oapi-codegen/issues/775 -// -// Note: The current implementation generates empty struct types for these -// properties instead of the ideal Go types (uuid.UUID for format:uuid, -// time.Time for format:date). This is a known limitation. -func TestAllOfWithFormatCompiles(t *testing.T) { - // The fact that this compiles proves the original issue is fixed - // (generation no longer errors on allOf + format) - obj := TestObject{ - UUIDProperty: &TestObjectUUIDProperty{}, - DateProperty: &TestObjectDateProperty{}, - } - - // Access the fields to ensure they exist - _ = obj.UUIDProperty - _ = obj.DateProperty -} - -// TestIdealBehavior documents the expected ideal behavior. -// Currently this would require changes to handle format-only allOf schemas. -func TestIdealBehavior(t *testing.T) { - t.Skip("TODO: allOf with format-only schemas should produce proper Go types (uuid.UUID, time.Time)") - - // Ideal behavior would be: - // type TestObject struct { - // UUIDProperty *uuid.UUID `json:"uuidProperty,omitempty"` - // DateProperty *time.Time `json:"dateProperty,omitempty"` - // } -} diff --git a/experimental/internal/codegen/test/issues/issue_775/spec.yaml b/experimental/internal/codegen/test/issues/issue_775/spec.yaml deleted file mode 100644 index 353485dd5b..0000000000 --- a/experimental/internal/codegen/test/issues/issue_775/spec.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Issue 775: allOf + format raises "can not merge incompatible formats" error -# https://github.com/oapi-codegen/oapi-codegen/issues/775 -# -# Using allOf to add a format to a base type should work without errors. -openapi: 3.0.0 -info: - title: Issue 775 Test - version: 1.0.0 -paths: {} -components: - schemas: - TestObject: - type: object - properties: - uuidProperty: - type: string - allOf: - - format: uuid - dateProperty: - type: string - allOf: - - format: date diff --git a/experimental/internal/codegen/test/issues/issue_832/doc.go b/experimental/internal/codegen/test/issues/issue_832/doc.go deleted file mode 100644 index a1e8c49610..0000000000 --- a/experimental/internal/codegen/test/issues/issue_832/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_832 tests x-go-type-name override for enum types. -// https://github.com/oapi-codegen/oapi-codegen/issues/832 -package issue_832 - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go deleted file mode 100644 index d9dd314469..0000000000 --- a/experimental/internal/codegen/test/issues/issue_832/output/types.gen.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Document -type Document struct { - Name *string `json:"name,omitempty" form:"name,omitempty"` - Status *string `json:"status,omitempty" form:"status,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *Document) ApplyDefaults() { -} - -// #/components/schemas/Document/properties/status -type Document_Status string - -const ( - Document_Status_one Document_Status = "one" - Document_Status_two Document_Status = "two" - Document_Status_three Document_Status = "three" - Document_Status_four Document_Status = "four" -) - -// #/components/schemas/DocumentStatus -type DocumentStatus struct { - Value *string `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *DocumentStatus) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/9RSPYvbQBDt9Sse54AaW1Lk5tg6EI4UKS5dCGFvPZb2sHaWnZFzgfz4IMkfkiHE7XWa", - "maf3wb4VnkR6wuO2NnjbNLzR35E2wXaEPSdQ6DsMK8lWaFWjmLJsvLb9S+G4K9lGv3G8o4bCcvADr5SP", - "2zrjSMFGb7AtqqLOfNizyYAjJfEcDPKqqIqPeQao1wMZ0Jvt4oEyYEfiko864v5kAPCNRG+t8pFS8ruZ", - "55g4UlJPkkWrrQyC5YnXjDwN6fQBDFA7aDztLuKfSU/XRBI5CMkZDuR1VeXX8cbnw9cvD7Ob46AUdA4H", - "chvjwbtRtXwVDvnyDohrqbO3W+BDor1Bviodd5EDBZVywkr5iV3fUdB8lra+N279fvM+q9Ve8uwKGXhO", - "qInyDD0LDOUx4JdXcueHvnbm6mKo19zT9Jto8qG5rGWUn8OW/TQX9Z+T0/8RYiyxwXcOtIb+4jW0TURr", - "7LlPPxaBnhfid8Y62kP/71x/AwAA//+qyWhEFgQAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_832/output/types_test.go b/experimental/internal/codegen/test/issues/issue_832/output/types_test.go deleted file mode 100644 index 8537eb4648..0000000000 --- a/experimental/internal/codegen/test/issues/issue_832/output/types_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestEnumTypeGeneration verifies that enum types in properties are generated. -// https://github.com/oapi-codegen/oapi-codegen/issues/832 -// -// Note: The x-go-type-name extension is not currently supported. The enum type -// is generated with a name derived from the property path rather than the -// specified x-go-type-name. -func TestEnumTypeGeneration(t *testing.T) { - // Enum constants should exist - _ = Document_Status_one - _ = Document_Status_two - _ = Document_Status_three - _ = Document_Status_four - - if string(Document_Status_one) != "one" { - t.Errorf("one = %q, want %q", Document_Status_one, "one") - } -} - -func TestDocumentWithStatus(t *testing.T) { - name := "test" - status := "one" - doc := Document{ - Name: &name, - Status: &status, - } - - data, err := json.Marshal(doc) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded Document - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if *decoded.Name != *doc.Name { - t.Errorf("Name = %q, want %q", *decoded.Name, *doc.Name) - } - if *decoded.Status != *doc.Status { - t.Errorf("Status = %q, want %q", *decoded.Status, *doc.Status) - } -} - -func TestDocumentStatusSchema(t *testing.T) { - // There's also a DocumentStatus schema (separate from the enum property) - value := "test-value" - ds := DocumentStatus{ - Value: &value, - } - - if *ds.Value != "test-value" { - t.Errorf("Value = %q, want %q", *ds.Value, "test-value") - } -} diff --git a/experimental/internal/codegen/test/issues/issue_832/spec.yaml b/experimental/internal/codegen/test/issues/issue_832/spec.yaml deleted file mode 100644 index fe2e387fdb..0000000000 --- a/experimental/internal/codegen/test/issues/issue_832/spec.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# Issue 832: x-go-type-name for enum types -# https://github.com/oapi-codegen/oapi-codegen/issues/832 -openapi: 3.0.2 -info: - version: '0.0.1' - title: example - description: | - Test x-go-type-name override for enum properties -paths: - /example: - get: - operationId: exampleGet - responses: - '200': - description: "OK" - content: - 'application/json': - schema: - $ref: '#/components/schemas/Document' - /example2: - get: - operationId: exampleGet2 - responses: - '200': - description: "OK" - content: - 'application/json': - schema: - $ref: '#/components/schemas/DocumentStatus' -components: - schemas: - Document: - type: object - properties: - name: - type: string - status: - x-go-type-name: Document_Status - type: string - enum: [one, two, three, four] - DocumentStatus: - type: object - properties: - value: - type: string diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go deleted file mode 100644 index db5bcd0016..0000000000 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_head_digit_operation_id tests operation IDs starting with digits. -// https://github.com/oapi-codegen/oapi-codegen/issues/head-digit-of-operation-id -package issue_head_digit_operation_id - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go deleted file mode 100644 index 3bbe71257a..0000000000 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types.gen.go +++ /dev/null @@ -1,69 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/paths//3gpp/foo/get/responses/200/content/application/json/schema -type N3GPPFooJSONResponse struct { - Value *string `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *N3GPPFooJSONResponse) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/2yPsXLqMBBFe33FHdMbP+hUM48wKaDIDyj2Ii9xtBrtQiZ/nzGBsUmiStK5ujq7wE71", - "TB77TCUYS8JuA7VQjFPEB1uPjiObW+CF1BTWB4PM0oqB3wjVens4/BepECmNlHAJA3fYCrijZHxkKuok", - "UwqZPdZ1U68cp6N4B1yoKEvyqJq6qf9VDjC2gTyeKHTYjA6PkqOOy8F6Hd8v1zHn5VGuZUAk+95gct11", - "HjfJGyqkWZKS3rPAqmmmA9CRtoWzXdX2zzPSSjJKNg8DIeeB2+tvy5NKeqSAtj29h5+3gH1m8pDXE7X2", - "C+YyjmA815zWJQxn+gvcW9UKp+i+AgAA//9y+0ZQ6gEAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go deleted file mode 100644 index df0bc5f952..0000000000 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/output/types_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" -) - -// TestOperationIdStartingWithDigit verifies that operation IDs starting with -// digits generate valid Go identifiers with an N prefix. -func TestOperationIdStartingWithDigit(t *testing.T) { - // The operationId is "3GPPFoo" which should generate N3GPPFooJSONResponse - // (N prefix added to make it a valid Go identifier) - value := "test" - response := N3GPPFooJSONResponse{ - Value: &value, - } - - if *response.Value != "test" { - t.Errorf("Value = %q, want %q", *response.Value, "test") - } -} - -func TestN3GPPFooJSONRoundTrip(t *testing.T) { - value := "test-value" - original := N3GPPFooJSONResponse{ - Value: &value, - } - - data, err := json.Marshal(original) - if err != nil { - t.Fatalf("Marshal failed: %v", err) - } - - var decoded N3GPPFooJSONResponse - if err := json.Unmarshal(data, &decoded); err != nil { - t.Fatalf("Unmarshal failed: %v", err) - } - - if *decoded.Value != *original.Value { - t.Errorf("Value = %q, want %q", *decoded.Value, *original.Value) - } -} - -// TestTypeNameIsValid ensures the type name is a valid Go identifier -func TestTypeNameIsValid(t *testing.T) { - // This test passes if it compiles - the type N3GPPFooJSONResponse - // must be a valid Go identifier - var _ N3GPPFooJSONResponse - var _ N3GPPFooJSONResponse -} diff --git a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml b/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml deleted file mode 100644 index 5bcd0f7d70..0000000000 --- a/experimental/internal/codegen/test/issues/issue_head_digit_operation_id/spec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Issue: Operation ID starting with digit -# Tests that operation IDs like "3GPPFoo" generate valid Go identifiers -openapi: 3.0.2 -info: - version: "0.0.1" - title: Head Digit Operation ID Test -paths: - /3gpp/foo: - get: - operationId: 3GPPFoo - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - properties: - value: - type: string diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go deleted file mode 100644 index e40f41cd2e..0000000000 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package issue_illegal_enum_names tests enum constant generation with edge cases. -// This tests various edge cases like empty strings, spaces, hyphens, leading digits, etc. -package issue_illegal_enum_names - -//go:generate go run ../../../../../cmd/oapi-codegen -package output -output output/types.gen.go spec.yaml diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go deleted file mode 100644 index ac2d373dde..0000000000 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types.gen.go +++ /dev/null @@ -1,80 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/Bar -type Bar string - -const ( - Bar_Value Bar = "" - Bar_Foo Bar = "Foo" - Bar_Bar Bar = "Bar" - Bar_Foo_Bar Bar = "Foo Bar" - Bar_Foo_Bar_1 Bar = "Foo-Bar" - Bar_Foo_1 Bar = "1Foo" - Bar__Foo Bar = " Foo" - Bar__Foo_ Bar = " Foo " - Bar__Foo__1 Bar = "_Foo_" - Bar_Value_1 Bar = "1" -) - -// #/paths//foo/get/responses/200/content/application/json/schema -type GetFooJSONResponse = []Bar - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/2SRQYujQBCF7/0rHpMFT6PO7M1jYAfCwu5l76ExFdOLVjVdlSz590urQU1u1veq3ie6", - "w0H1Sg0OfU+d70F8HcB+IHU7/CE1nVArrObZ0BFT8haE8S/YBTefglwVdOoIrVdSJ5HYx9Dge1mXn84F", - "PkvjAAvWr1Q/cu+vrBpFDrhR0iDcoC7rsnYuertovqzOMjYAHdn0AEicX+RwajL/EpmTRBqFlfSxCnzW", - "9TIAJ9I2hWij7ffPVdIKG7GtlwEfYx/aUVb9VeFtCmh7ocE/U8DukRr4lPz9JQtGg76eAN8SnRsUu6qV", - "IQoTm1aTQKu9T4VzS5Dv52yq2vv06JzkailwN6P8KxflO4piNSzfL097n7bZK3nfko9tQZFXimeANTl+", - "iRxX89vHm/sfAAD//5W/OQySAgAA", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go deleted file mode 100644 index 65a49f009f..0000000000 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/output/types_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package output - -import ( - "testing" -) - -// TestIllegalEnumNames verifies that enum constants with various edge case values -// are generated with valid Go identifiers. -func TestIllegalEnumNames(t *testing.T) { - // All these enum constants should exist and have valid Go names - tests := []struct { - name string - constant Bar - value string - }{ - {"empty string", Bar_Value, ""}, - {"Foo", Bar_Foo, "Foo"}, - {"Bar", Bar_Bar, "Bar"}, - {"Foo Bar (with space)", Bar_Foo_Bar, "Foo Bar"}, - {"Foo-Bar (with hyphen)", Bar_Foo_Bar_1, "Foo-Bar"}, - {"1Foo (leading digit)", Bar_Foo_1, "1Foo"}, - {" Foo (leading space)", Bar__Foo, " Foo"}, - {" Foo (leading and trailing space)", Bar__Foo_, " Foo "}, - {"_Foo_ (underscores)", Bar__Foo__1, "_Foo_"}, - {"1 (just digit)", Bar_Value_1, "1"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if string(tt.constant) != tt.value { - t.Errorf("constant %q = %q, want %q", tt.name, tt.constant, tt.value) - } - }) - } -} - -func TestBarCanBeUsedInSlice(t *testing.T) { - // The response type is []Bar - response := GetFooJSONResponse{ - Bar_Foo, - Bar_Bar, - Bar_Value, // empty string - } - - if len(response) != 3 { - t.Errorf("response length = %d, want 3", len(response)) - } - if response[0] != "Foo" { - t.Errorf("response[0] = %q, want %q", response[0], "Foo") - } -} diff --git a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml b/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml deleted file mode 100644 index 5d80f246cf..0000000000 --- a/experimental/internal/codegen/test/issues/issue_illegal_enum_names/spec.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Issue: Illegal enum names -# Tests enum constant generation with various edge cases -openapi: 3.0.2 - -info: - title: Illegal Enum Names Test - version: 0.0.0 - -paths: - /foo: - get: - operationId: getFoo - responses: - 200: - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Bar' - -components: - schemas: - Bar: - type: string - enum: - - '' - - Foo - - Bar - - Foo Bar - - Foo-Bar - - 1Foo - - ' Foo' - - ' Foo ' - - _Foo_ - - "1" diff --git a/experimental/internal/codegen/test/nested_aggregate/doc.go b/experimental/internal/codegen/test/nested_aggregate/doc.go deleted file mode 100644 index 6d934ad0d9..0000000000 --- a/experimental/internal/codegen/test/nested_aggregate/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -package nested_aggregate - -//go:generate go run ../../../../cmd/oapi-codegen -package output -output output/nested_aggregate.gen.go nested_aggregate.yaml diff --git a/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml b/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml deleted file mode 100644 index 7a9c081ec2..0000000000 --- a/experimental/internal/codegen/test/nested_aggregate/nested_aggregate.yaml +++ /dev/null @@ -1,62 +0,0 @@ -openapi: "3.1.0" -info: - title: Nested Aggregate Test - version: "1.0" -paths: {} -components: - schemas: - # Case 1: Array with anyOf items - ArrayOfAnyOf: - type: array - items: - anyOf: - - type: string - - type: object - properties: - id: - type: integer - - # Case 2: Object with anyOf property - ObjectWithAnyOfProperty: - type: object - properties: - value: - anyOf: - - type: string - - type: integer - - # Case 3: Object with oneOf property containing inline objects - ObjectWithOneOfProperty: - type: object - properties: - variant: - oneOf: - - type: object - properties: - kind: - type: string - name: - type: string - - type: object - properties: - kind: - type: string - count: - type: integer - - # Case 4: allOf containing oneOf - AllOfWithOneOf: - allOf: - - type: object - properties: - base: - type: string - - oneOf: - - type: object - properties: - optionA: - type: boolean - - type: object - properties: - optionB: - type: integer diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go deleted file mode 100644 index 8e9cb4c44b..0000000000 --- a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate.gen.go +++ /dev/null @@ -1,400 +0,0 @@ -// Code generated by oapi-codegen; DO NOT EDIT. - -package output - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "sync" -) - -// #/components/schemas/ArrayOfAnyOf -type ArrayOfAnyOf = []ArrayOfAnyOfItem - -// #/components/schemas/ArrayOfAnyOf/items -type ArrayOfAnyOfItem struct { - String0 *string - ArrayOfAnyOfAnyOf1 *ArrayOfAnyOfAnyOf1 -} - -func (u ArrayOfAnyOfItem) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.ArrayOfAnyOfAnyOf1 != nil { - data, err := json.Marshal(u.ArrayOfAnyOfAnyOf1) - if err != nil { - return nil, err - } - var m map[string]any - if err := json.Unmarshal(data, &m); err == nil { - for k, v := range m { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (u *ArrayOfAnyOfItem) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 ArrayOfAnyOfAnyOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.ArrayOfAnyOfAnyOf1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ArrayOfAnyOfItem) ApplyDefaults() { - if u.ArrayOfAnyOfAnyOf1 != nil { - u.ArrayOfAnyOfAnyOf1.ApplyDefaults() - } -} - -// #/components/schemas/ArrayOfAnyOf/items/anyOf/1 -type ArrayOfAnyOfAnyOf1 struct { - ID *int `json:"id,omitempty" form:"id,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ArrayOfAnyOfAnyOf1) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithAnyOfProperty -type ObjectWithAnyOfProperty struct { - Value *ObjectWithAnyOfPropertyValue `json:"value,omitempty" form:"value,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithAnyOfProperty) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithAnyOfProperty/properties/value -type ObjectWithAnyOfPropertyValue struct { - String0 *string - Int1 *int -} - -func (u ObjectWithAnyOfPropertyValue) MarshalJSON() ([]byte, error) { - if u.String0 != nil { - return json.Marshal(u.String0) - } - if u.Int1 != nil { - return json.Marshal(u.Int1) - } - return []byte("null"), nil -} - -func (u *ObjectWithAnyOfPropertyValue) UnmarshalJSON(data []byte) error { - var v0 string - if err := json.Unmarshal(data, &v0); err == nil { - u.String0 = &v0 - } - - var v1 int - if err := json.Unmarshal(data, &v1); err == nil { - u.Int1 = &v1 - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ObjectWithAnyOfPropertyValue) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithOneOfProperty -type ObjectWithOneOfProperty struct { - Variant *ObjectWithOneOfPropertyVariant `json:"variant,omitempty" form:"variant,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithOneOfProperty) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithOneOfProperty/properties/variant -type ObjectWithOneOfPropertyVariant struct { - ObjectWithOneOfPropertyVariantOneOf0 *ObjectWithOneOfPropertyVariantOneOf0 - ObjectWithOneOfPropertyVariantOneOf1 *ObjectWithOneOfPropertyVariantOneOf1 -} - -func (u ObjectWithOneOfPropertyVariant) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.ObjectWithOneOfPropertyVariantOneOf0 != nil { - count++ - data, err = json.Marshal(u.ObjectWithOneOfPropertyVariantOneOf0) - if err != nil { - return nil, err - } - } - if u.ObjectWithOneOfPropertyVariantOneOf1 != nil { - count++ - data, err = json.Marshal(u.ObjectWithOneOfPropertyVariantOneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("ObjectWithOneOfPropertyVariant: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *ObjectWithOneOfPropertyVariant) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 ObjectWithOneOfPropertyVariantOneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.ObjectWithOneOfPropertyVariantOneOf0 = &v0 - successCount++ - } - - var v1 ObjectWithOneOfPropertyVariantOneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.ObjectWithOneOfPropertyVariantOneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("ObjectWithOneOfPropertyVariant: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *ObjectWithOneOfPropertyVariant) ApplyDefaults() { - if u.ObjectWithOneOfPropertyVariantOneOf0 != nil { - u.ObjectWithOneOfPropertyVariantOneOf0.ApplyDefaults() - } - if u.ObjectWithOneOfPropertyVariantOneOf1 != nil { - u.ObjectWithOneOfPropertyVariantOneOf1.ApplyDefaults() - } -} - -// #/components/schemas/ObjectWithOneOfProperty/properties/variant/oneOf/0 -type ObjectWithOneOfPropertyVariantOneOf0 struct { - Kind *string `json:"kind,omitempty" form:"kind,omitempty"` - Name *string `json:"name,omitempty" form:"name,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithOneOfPropertyVariantOneOf0) ApplyDefaults() { -} - -// #/components/schemas/ObjectWithOneOfProperty/properties/variant/oneOf/1 -type ObjectWithOneOfPropertyVariantOneOf1 struct { - Kind *string `json:"kind,omitempty" form:"kind,omitempty"` - Count *int `json:"count,omitempty" form:"count,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *ObjectWithOneOfPropertyVariantOneOf1) ApplyDefaults() { -} - -// #/components/schemas/AllOfWithOneOf -type AllOfWithOneOf struct { - Base *string `json:"base,omitempty" form:"base,omitempty"` - AllOfWithOneOfAllOf1 *AllOfWithOneOfAllOf1 `json:"-"` -} - -func (s AllOfWithOneOf) MarshalJSON() ([]byte, error) { - result := make(map[string]any) - - if s.Base != nil { - result["base"] = s.Base - } - - if s.AllOfWithOneOfAllOf1 != nil { - unionData, err := json.Marshal(s.AllOfWithOneOfAllOf1) - if err != nil { - return nil, err - } - var unionMap map[string]any - if err := json.Unmarshal(unionData, &unionMap); err == nil { - for k, v := range unionMap { - result[k] = v - } - } - } - - return json.Marshal(result) -} - -func (s *AllOfWithOneOf) UnmarshalJSON(data []byte) error { - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } - - if v, ok := raw["base"]; ok { - var val string - if err := json.Unmarshal(v, &val); err != nil { - return err - } - s.Base = &val - } - - var AllOfWithOneOfAllOf1Val AllOfWithOneOfAllOf1 - if err := json.Unmarshal(data, &AllOfWithOneOfAllOf1Val); err != nil { - return err - } - s.AllOfWithOneOfAllOf1 = &AllOfWithOneOfAllOf1Val - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithOneOf) ApplyDefaults() { -} - -// #/components/schemas/AllOfWithOneOf/allOf/1 -type AllOfWithOneOfAllOf1 struct { - AllOfWithOneOfAllOf1OneOf0 *AllOfWithOneOfAllOf1OneOf0 - AllOfWithOneOfAllOf1OneOf1 *AllOfWithOneOfAllOf1OneOf1 -} - -func (u AllOfWithOneOfAllOf1) MarshalJSON() ([]byte, error) { - var count int - var data []byte - var err error - - if u.AllOfWithOneOfAllOf1OneOf0 != nil { - count++ - data, err = json.Marshal(u.AllOfWithOneOfAllOf1OneOf0) - if err != nil { - return nil, err - } - } - if u.AllOfWithOneOfAllOf1OneOf1 != nil { - count++ - data, err = json.Marshal(u.AllOfWithOneOfAllOf1OneOf1) - if err != nil { - return nil, err - } - } - - if count != 1 { - return nil, fmt.Errorf("AllOfWithOneOfAllOf1: exactly one member must be set, got %d", count) - } - - return data, nil -} - -func (u *AllOfWithOneOfAllOf1) UnmarshalJSON(data []byte) error { - var successCount int - - var v0 AllOfWithOneOfAllOf1OneOf0 - if err := json.Unmarshal(data, &v0); err == nil { - u.AllOfWithOneOfAllOf1OneOf0 = &v0 - successCount++ - } - - var v1 AllOfWithOneOfAllOf1OneOf1 - if err := json.Unmarshal(data, &v1); err == nil { - u.AllOfWithOneOfAllOf1OneOf1 = &v1 - successCount++ - } - - if successCount != 1 { - return fmt.Errorf("AllOfWithOneOfAllOf1: expected exactly one type to match, got %d", successCount) - } - - return nil -} - -// ApplyDefaults sets default values for fields that are nil. -func (u *AllOfWithOneOfAllOf1) ApplyDefaults() { - if u.AllOfWithOneOfAllOf1OneOf0 != nil { - u.AllOfWithOneOfAllOf1OneOf0.ApplyDefaults() - } - if u.AllOfWithOneOfAllOf1OneOf1 != nil { - u.AllOfWithOneOfAllOf1OneOf1.ApplyDefaults() - } -} - -// #/components/schemas/AllOfWithOneOf/allOf/1/oneOf/0 -type AllOfWithOneOfAllOf1OneOf0 struct { - OptionA *bool `json:"optionA,omitempty" form:"optionA,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithOneOfAllOf1OneOf0) ApplyDefaults() { -} - -// #/components/schemas/AllOfWithOneOf/allOf/1/oneOf/1 -type AllOfWithOneOfAllOf1OneOf1 struct { - OptionB *int `json:"optionB,omitempty" form:"optionB,omitempty"` -} - -// ApplyDefaults sets default values for fields that are nil. -func (s *AllOfWithOneOfAllOf1OneOf1) ApplyDefaults() { -} - -// Base64-encoded, gzip-compressed OpenAPI spec. -var swaggerSpecJSON = []string{ - "H4sIAAAAAAAC/7yTQY/TMBCF7/kVT+W8K5bl5FvgTjggcXbTSTKQjC17WlQh/juKk9KkTVqBKnpq5nnG", - "75uXOE9iPRtsXp9fnt9uMpbKmQxQ1pYMPlFU2iGv60C1VcIXipoBBwqRnRhsUpe32kSDn7+y0nXeCYnG", - "fkosG+ps+gu8wUcbCS8GeQj2iB+sDawciwqs1MV0KElFlffloQ3QoycD2ytjJZ0/yRiGnB+Bp7EnamCp", - "FwS3/UalTgTAB+cpKFM0szrAu8vKyROLUk0hm/K9MyjS9CngOHzwP8hfWZuE+XnU5rgzh0veDrbd09TY", - "1RZu7OEsLSG8zhGc0AQBpRO1LCw1WFoWGr3GC7iib/tnuMBWdEqTXCzjLaR5K0/gO8tCpljfVv8T29Ff", - "Nf1fe6Xbzxd2/1V9b2DbtqimkaY1D59iL/0J8jQ5NZyvWWVc49vaeLXFRa6nhybuvLKTfH0/W+dasvLI", - "2z7cT+N3AAAA//8nzKKtgAUAAA==", -} - -// decodeSwaggerSpec decodes and decompresses the embedded spec. -func decodeSwaggerSpec() ([]byte, error) { - joined := strings.Join(swaggerSpecJSON, "") - raw, err := base64.StdEncoding.DecodeString(joined) - if err != nil { - return nil, fmt.Errorf("decoding base64: %w", err) - } - r, err := gzip.NewReader(bytes.NewReader(raw)) - if err != nil { - return nil, fmt.Errorf("creating gzip reader: %w", err) - } - defer r.Close() - var out bytes.Buffer - if _, err := out.ReadFrom(r); err != nil { - return nil, fmt.Errorf("decompressing: %w", err) - } - return out.Bytes(), nil -} - -// decodeSwaggerSpecCached returns a closure that caches the decoded spec. -func decodeSwaggerSpecCached() func() ([]byte, error) { - var cached []byte - var cachedErr error - var once sync.Once - return func() ([]byte, error) { - once.Do(func() { - cached, cachedErr = decodeSwaggerSpec() - }) - return cached, cachedErr - } -} - -var swaggerSpec = decodeSwaggerSpecCached() - -// GetSwaggerSpecJSON returns the raw OpenAPI spec as JSON bytes. -func GetSwaggerSpecJSON() ([]byte, error) { - return swaggerSpec() -} diff --git a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go b/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go deleted file mode 100644 index e70e8cb49e..0000000000 --- a/experimental/internal/codegen/test/nested_aggregate/output/nested_aggregate_test.go +++ /dev/null @@ -1,332 +0,0 @@ -package output - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func ptr[T any](v T) *T { - return &v -} - -// TestArrayOfAnyOf tests marshaling/unmarshaling of arrays with anyOf items -func TestArrayOfAnyOf(t *testing.T) { - t.Run("unmarshal string item", func(t *testing.T) { - input := `["hello", "world"]` - var arr ArrayOfAnyOf - err := json.Unmarshal([]byte(input), &arr) - require.NoError(t, err) - require.Len(t, arr, 2) - - // String items should populate the string field - assert.NotNil(t, arr[0].String0) - assert.Equal(t, "hello", *arr[0].String0) - assert.NotNil(t, arr[1].String0) - assert.Equal(t, "world", *arr[1].String0) - }) - - t.Run("unmarshal object item", func(t *testing.T) { - input := `[{"id": 42}]` - var arr ArrayOfAnyOf - err := json.Unmarshal([]byte(input), &arr) - require.NoError(t, err) - require.Len(t, arr, 1) - - // Object item should populate the object field - assert.NotNil(t, arr[0].ArrayOfAnyOfAnyOf1) - assert.NotNil(t, arr[0].ArrayOfAnyOfAnyOf1.ID) - assert.Equal(t, 42, *arr[0].ArrayOfAnyOfAnyOf1.ID) - }) - - t.Run("unmarshal mixed items", func(t *testing.T) { - input := `["hello", {"id": 1}, "world", {"id": 2}]` - var arr ArrayOfAnyOf - err := json.Unmarshal([]byte(input), &arr) - require.NoError(t, err) - require.Len(t, arr, 4) - - assert.NotNil(t, arr[0].String0) - assert.Equal(t, "hello", *arr[0].String0) - - assert.NotNil(t, arr[1].ArrayOfAnyOfAnyOf1) - assert.Equal(t, 1, *arr[1].ArrayOfAnyOfAnyOf1.ID) - - assert.NotNil(t, arr[2].String0) - assert.Equal(t, "world", *arr[2].String0) - - assert.NotNil(t, arr[3].ArrayOfAnyOfAnyOf1) - assert.Equal(t, 2, *arr[3].ArrayOfAnyOfAnyOf1.ID) - }) - - t.Run("marshal string item", func(t *testing.T) { - arr := ArrayOfAnyOf{ - {String0: ptr("hello")}, - } - data, err := json.Marshal(arr) - require.NoError(t, err) - assert.JSONEq(t, `["hello"]`, string(data)) - }) - - t.Run("marshal object item", func(t *testing.T) { - arr := ArrayOfAnyOf{ - {ArrayOfAnyOfAnyOf1: &ArrayOfAnyOfAnyOf1{ID: ptr(42)}}, - } - data, err := json.Marshal(arr) - require.NoError(t, err) - assert.JSONEq(t, `[{"id": 42}]`, string(data)) - }) - - t.Run("round trip mixed", func(t *testing.T) { - original := ArrayOfAnyOf{ - {String0: ptr("test")}, - {ArrayOfAnyOfAnyOf1: &ArrayOfAnyOfAnyOf1{ID: ptr(99)}}, - } - - data, err := json.Marshal(original) - require.NoError(t, err) - - var decoded ArrayOfAnyOf - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - require.Len(t, decoded, 2) - assert.Equal(t, "test", *decoded[0].String0) - assert.Equal(t, 99, *decoded[1].ArrayOfAnyOfAnyOf1.ID) - }) -} - -// TestObjectWithAnyOfProperty tests marshaling/unmarshaling of objects with anyOf properties -func TestObjectWithAnyOfProperty(t *testing.T) { - t.Run("unmarshal string value", func(t *testing.T) { - input := `{"value": "hello"}` - var obj ObjectWithAnyOfProperty - err := json.Unmarshal([]byte(input), &obj) - require.NoError(t, err) - - require.NotNil(t, obj.Value) - assert.NotNil(t, obj.Value.String0) - assert.Equal(t, "hello", *obj.Value.String0) - }) - - t.Run("unmarshal integer value", func(t *testing.T) { - input := `{"value": 42}` - var obj ObjectWithAnyOfProperty - err := json.Unmarshal([]byte(input), &obj) - require.NoError(t, err) - - require.NotNil(t, obj.Value) - assert.NotNil(t, obj.Value.Int1) - assert.Equal(t, 42, *obj.Value.Int1) - }) - - t.Run("marshal string value", func(t *testing.T) { - obj := ObjectWithAnyOfProperty{ - Value: &ObjectWithAnyOfPropertyValue{ - String0: ptr("hello"), - }, - } - data, err := json.Marshal(obj) - require.NoError(t, err) - assert.JSONEq(t, `{"value": "hello"}`, string(data)) - }) - - t.Run("marshal integer value", func(t *testing.T) { - obj := ObjectWithAnyOfProperty{ - Value: &ObjectWithAnyOfPropertyValue{ - Int1: ptr(42), - }, - } - data, err := json.Marshal(obj) - require.NoError(t, err) - assert.JSONEq(t, `{"value": 42}`, string(data)) - }) - - t.Run("round trip string", func(t *testing.T) { - original := ObjectWithAnyOfProperty{ - Value: &ObjectWithAnyOfPropertyValue{String0: ptr("test")}, - } - - data, err := json.Marshal(original) - require.NoError(t, err) - - var decoded ObjectWithAnyOfProperty - err = json.Unmarshal(data, &decoded) - require.NoError(t, err) - - require.NotNil(t, decoded.Value) - assert.Equal(t, "test", *decoded.Value.String0) - }) -} - -// TestObjectWithOneOfProperty tests marshaling/unmarshaling of objects with oneOf properties -func TestObjectWithOneOfProperty(t *testing.T) { - t.Run("unmarshal ambiguous input errors", func(t *testing.T) { - // Both variants have optional "kind" field, so this JSON matches both - // oneOf requires exactly one match, so this should error - input := `{"variant": {"kind": "person", "name": "Alice"}}` - var obj ObjectWithOneOfProperty - err := json.Unmarshal([]byte(input), &obj) - require.Error(t, err) - assert.Contains(t, err.Error(), "expected exactly one type to match, got 2") - }) - - t.Run("unmarshal unambiguous variant 0", func(t *testing.T) { - // Only variant 0 has "name" as a field that can be set - // But since all fields are optional, both variants still match - // This demonstrates why discriminators are important for oneOf - input := `{"variant": {"name": "Alice"}}` - var obj ObjectWithOneOfProperty - err := json.Unmarshal([]byte(input), &obj) - // Still ambiguous because both variants can unmarshal (missing fields are just nil) - require.Error(t, err) - }) - - t.Run("unmarshal unambiguous variant 1", func(t *testing.T) { - // Only variant 1 has "count" field - // But since all fields are optional, both variants still match - input := `{"variant": {"count": 10}}` - var obj ObjectWithOneOfProperty - err := json.Unmarshal([]byte(input), &obj) - // Still ambiguous because both variants can unmarshal (missing fields are just nil) - require.Error(t, err) - }) - - t.Run("marshal variant 0", func(t *testing.T) { - obj := ObjectWithOneOfProperty{ - Variant: &ObjectWithOneOfPropertyVariant{ - ObjectWithOneOfPropertyVariantOneOf0: &ObjectWithOneOfPropertyVariantOneOf0{ - Kind: ptr("person"), - Name: ptr("Alice"), - }, - }, - } - data, err := json.Marshal(obj) - require.NoError(t, err) - assert.JSONEq(t, `{"variant": {"kind": "person", "name": "Alice"}}`, string(data)) - }) - - t.Run("marshal variant 1", func(t *testing.T) { - obj := ObjectWithOneOfProperty{ - Variant: &ObjectWithOneOfPropertyVariant{ - ObjectWithOneOfPropertyVariantOneOf1: &ObjectWithOneOfPropertyVariantOneOf1{ - Kind: ptr("counter"), - Count: ptr(10), - }, - }, - } - data, err := json.Marshal(obj) - require.NoError(t, err) - assert.JSONEq(t, `{"variant": {"kind": "counter", "count": 10}}`, string(data)) - }) - - t.Run("marshal fails with zero variants set", func(t *testing.T) { - obj := ObjectWithOneOfProperty{ - Variant: &ObjectWithOneOfPropertyVariant{}, - } - _, err := json.Marshal(obj) - assert.Error(t, err) - assert.Contains(t, err.Error(), "exactly one member must be set") - }) - - t.Run("marshal fails with two variants set", func(t *testing.T) { - obj := ObjectWithOneOfProperty{ - Variant: &ObjectWithOneOfPropertyVariant{ - ObjectWithOneOfPropertyVariantOneOf0: &ObjectWithOneOfPropertyVariantOneOf0{ - Kind: ptr("person"), - Name: ptr("Alice"), - }, - ObjectWithOneOfPropertyVariantOneOf1: &ObjectWithOneOfPropertyVariantOneOf1{ - Kind: ptr("counter"), - Count: ptr(10), - }, - }, - } - _, err := json.Marshal(obj) - assert.Error(t, err) - assert.Contains(t, err.Error(), "exactly one member must be set") - }) -} - -// TestAllOfWithOneOf tests marshaling/unmarshaling of allOf containing oneOf -func TestAllOfWithOneOf(t *testing.T) { - t.Run("unmarshal with optionA - ambiguous oneOf errors", func(t *testing.T) { - // The nested oneOf has same ambiguity issue - both variants match - input := `{"base": "test", "optionA": true}` - var obj AllOfWithOneOf - err := json.Unmarshal([]byte(input), &obj) - // The nested AllOfWithOneOfAllOf1 (oneOf) will error due to ambiguity - require.Error(t, err) - assert.Contains(t, err.Error(), "expected exactly one type to match") - }) - - t.Run("unmarshal with optionB - ambiguous oneOf errors", func(t *testing.T) { - input := `{"base": "test", "optionB": 42}` - var obj AllOfWithOneOf - err := json.Unmarshal([]byte(input), &obj) - require.Error(t, err) - assert.Contains(t, err.Error(), "expected exactly one type to match") - }) - - t.Run("marshal with optionA", func(t *testing.T) { - obj := AllOfWithOneOf{ - Base: ptr("test"), - AllOfWithOneOfAllOf1: &AllOfWithOneOfAllOf1{ - AllOfWithOneOfAllOf1OneOf0: &AllOfWithOneOfAllOf1OneOf0{ - OptionA: ptr(true), - }, - }, - } - - data, err := json.Marshal(obj) - require.NoError(t, err) - - // Should contain both base and optionA merged - var m map[string]any - err = json.Unmarshal(data, &m) - require.NoError(t, err) - - assert.Equal(t, "test", m["base"]) - assert.Equal(t, true, m["optionA"]) - }) - - t.Run("marshal with optionB", func(t *testing.T) { - obj := AllOfWithOneOf{ - Base: ptr("test"), - AllOfWithOneOfAllOf1: &AllOfWithOneOfAllOf1{ - AllOfWithOneOfAllOf1OneOf1: &AllOfWithOneOfAllOf1OneOf1{ - OptionB: ptr(42), - }, - }, - } - - data, err := json.Marshal(obj) - require.NoError(t, err) - - var m map[string]any - err = json.Unmarshal(data, &m) - require.NoError(t, err) - - assert.Equal(t, "test", m["base"]) - assert.Equal(t, float64(42), m["optionB"]) // JSON numbers are float64 - }) - - t.Run("marshal with nil union", func(t *testing.T) { - obj := AllOfWithOneOf{ - Base: ptr("only-base"), - } - - data, err := json.Marshal(obj) - require.NoError(t, err) - - var m map[string]any - err = json.Unmarshal(data, &m) - require.NoError(t, err) - - assert.Equal(t, "only-base", m["base"]) - assert.NotContains(t, m, "optionA") - assert.NotContains(t, m, "optionB") - }) -} diff --git a/experimental/internal/codegen/typegen.go b/experimental/internal/codegen/typegen.go deleted file mode 100644 index e27424bff0..0000000000 --- a/experimental/internal/codegen/typegen.go +++ /dev/null @@ -1,918 +0,0 @@ -package codegen - -import ( - "fmt" - "sort" - "strings" - - "github.com/pb33f/libopenapi/datamodel/high/base" -) - -// TypeGenerator converts OpenAPI schemas to Go type expressions. -// It tracks required imports and handles recursive type references. -type TypeGenerator struct { - typeMapping TypeMapping - converter *NameConverter - importResolver *ImportResolver - tagGenerator *StructTagGenerator - imports map[string]string // path -> alias (empty string = no alias) - - // schemaIndex maps JSON pointer refs to their descriptors - schemaIndex map[string]*SchemaDescriptor - - // requiredTemplates tracks which custom type templates are needed - requiredTemplates map[string]bool -} - -// NewTypeGenerator creates a TypeGenerator with the given configuration. -func NewTypeGenerator(typeMapping TypeMapping, converter *NameConverter, importResolver *ImportResolver, tagGenerator *StructTagGenerator) *TypeGenerator { - return &TypeGenerator{ - typeMapping: typeMapping, - converter: converter, - importResolver: importResolver, - tagGenerator: tagGenerator, - imports: make(map[string]string), - schemaIndex: make(map[string]*SchemaDescriptor), - requiredTemplates: make(map[string]bool), - } -} - -// IndexSchemas builds a lookup table from JSON pointer to schema descriptor. -// This is called before generation to enable $ref resolution. -func (g *TypeGenerator) IndexSchemas(schemas []*SchemaDescriptor) { - for _, s := range schemas { - ref := s.Path.String() - g.schemaIndex[ref] = s - } -} - -// AddImport records an import path needed by the generated code. -func (g *TypeGenerator) AddImport(path string) { - if path != "" { - g.imports[path] = "" - } -} - -// AddImportAlias records an import path with an alias. -func (g *TypeGenerator) AddImportAlias(path, alias string) { - if path != "" { - g.imports[path] = alias - } -} - -// AddJSONImport adds encoding/json import (used by marshal/unmarshal code). -func (g *TypeGenerator) AddJSONImport() { - g.AddImport("encoding/json") -} - -// AddJSONImports adds encoding/json and fmt imports (used by oneOf marshal/unmarshal code). -func (g *TypeGenerator) AddJSONImports() { - g.AddImport("encoding/json") - g.AddImport("fmt") -} - -// AddNullableTemplate adds the nullable type template to the output. -func (g *TypeGenerator) AddNullableTemplate() { - g.addTemplate("nullable") -} - -// Imports returns the collected imports as a map[path]alias. -func (g *TypeGenerator) Imports() map[string]string { - return g.imports -} - -// RequiredTemplates returns the set of template names needed for custom types. -func (g *TypeGenerator) RequiredTemplates() map[string]bool { - return g.requiredTemplates -} - -// addTemplate records that a custom type template is needed. -func (g *TypeGenerator) addTemplate(templateName string) { - if templateName != "" { - g.requiredTemplates[templateName] = true - } -} - -// GoTypeExpr returns the Go type expression for a schema descriptor. -// This handles references by looking up the target schema's name, -// and inline schemas by generating the appropriate Go type. -func (g *TypeGenerator) GoTypeExpr(desc *SchemaDescriptor) string { - // Handle $ref - return the referenced type's name - if desc.IsReference() { - // Check for external reference first - if desc.IsExternalReference() { - return g.externalRefType(desc) - } - - // Internal reference - look up in schema index - if target, ok := g.schemaIndex[desc.Ref]; ok { - return target.ShortName - } - // Fallback for unresolved references - return "any" - } - - return g.goTypeForSchema(desc.Schema, desc) -} - -// externalRefType resolves an external reference to a qualified Go type. -// Returns "any" if the external ref cannot be resolved. -func (g *TypeGenerator) externalRefType(desc *SchemaDescriptor) string { - filePath, internalPath := desc.ParseExternalRef() - if filePath == "" { - return "any" - } - - // Look up import mapping - if g.importResolver == nil { - // No import resolver configured - can't resolve external refs - return "any" - } - - imp := g.importResolver.Resolve(filePath) - if imp == nil { - // External file not in import mapping - return "any" - } - - // Extract type name from internal path (e.g., #/components/schemas/Pet -> Pet) - typeName := extractTypeNameFromRef(internalPath, g.converter) - if typeName == "" { - return "any" - } - - // If alias is empty, it's the current package (marked with "-") - if imp.Alias == "" { - return typeName - } - - // Add the import - g.AddImportAlias(imp.Path, imp.Alias) - - // Return qualified type - return imp.Alias + "." + typeName -} - -// extractTypeNameFromRef extracts a Go type name from an internal ref path. -// e.g., "#/components/schemas/Pet" -> "Pet" -func extractTypeNameFromRef(ref string, converter *NameConverter) string { - // Remove leading #/ - ref = strings.TrimPrefix(ref, "#/") - parts := strings.Split(ref, "/") - - if len(parts) < 3 { - return "" - } - - // For #/components/schemas/TypeName, the type name is the last part - // We assume external refs point to component schemas - typeName := parts[len(parts)-1] - return converter.ToTypeName(typeName) -} - -// goTypeForSchema generates a Go type expression from an OpenAPI schema. -// The desc parameter provides context (path, parent) for complex types. -func (g *TypeGenerator) goTypeForSchema(schema *base.Schema, desc *SchemaDescriptor) string { - if schema == nil { - return "any" - } - - // Handle composition types - if len(schema.AllOf) > 0 { - return g.allOfType(desc) - } - if len(schema.AnyOf) > 0 { - return g.anyOfType(desc) - } - if len(schema.OneOf) > 0 { - return g.oneOfType(desc) - } - - // Get the primary type from the type array - // OpenAPI 3.1 allows type to be an array like ["string", "null"] - primaryType := getPrimaryType(schema) - - // Check if this is a nullable primitive - wrap in Nullable[T] - nullable := isNullable(schema) - isPrimitive := primaryType == "string" || primaryType == "integer" || primaryType == "number" || primaryType == "boolean" - - var baseType string - switch primaryType { - case "object": - return g.objectType(schema, desc) - case "array": - return g.arrayType(schema, desc) - case "string": - baseType = g.stringType(schema) - case "integer": - baseType = g.integerType(schema) - case "number": - baseType = g.numberType(schema) - case "boolean": - baseType = g.booleanType(schema) - default: - // Unknown or empty type - could be a free-form object - if schema.Properties != nil && schema.Properties.Len() > 0 { - return g.objectType(schema, desc) - } - return "any" - } - - // Wrap nullable primitives in Nullable[T] - if nullable && isPrimitive { - g.AddNullableTemplate() - return "Nullable[" + baseType + "]" - } - - return baseType -} - -// getPrimaryType extracts the primary (non-null) type from a schema. -// OpenAPI 3.1 supports type arrays like ["string", "null"] for nullable. -func getPrimaryType(schema *base.Schema) string { - if len(schema.Type) == 0 { - return "" - } - for _, t := range schema.Type { - if t != "null" { - return t - } - } - return schema.Type[0] -} - -// objectType generates the Go type for an object schema. -// Simple objects with only additionalProperties become maps. -// Objects with properties become named struct types. -func (g *TypeGenerator) objectType(schema *base.Schema, desc *SchemaDescriptor) string { - hasProperties := schema.Properties != nil && schema.Properties.Len() > 0 - hasAdditionalProps := schema.AdditionalProperties != nil - - // Pure map case: no properties, only additionalProperties - if !hasProperties && hasAdditionalProps { - return g.mapType(schema, desc) - } - - // Empty object (no properties, no additionalProperties) - if !hasProperties && !hasAdditionalProps { - return "map[string]any" - } - - // Struct case: has properties (with or without additionalProperties) - // Return the type name - actual struct definition is generated separately - if desc != nil && desc.ShortName != "" { - return desc.ShortName - } - return "any" -} - -// mapType generates a map[string]T type for additionalProperties schemas. -func (g *TypeGenerator) mapType(schema *base.Schema, desc *SchemaDescriptor) string { - if schema.AdditionalProperties == nil { - return "map[string]any" - } - - // additionalProperties can be a boolean or a schema - // If it's a schema proxy (A), get the value type - if schema.AdditionalProperties.A != nil { - valueSchema := schema.AdditionalProperties.A.Schema() - if valueSchema != nil { - valueType := g.goTypeForSchema(valueSchema, nil) - return "map[string]" + valueType - } - } - - // additionalProperties: true or just present - return "map[string]any" -} - -// arrayType generates a []T type for array schemas. -func (g *TypeGenerator) arrayType(schema *base.Schema, desc *SchemaDescriptor) string { - if schema.Items == nil || schema.Items.A == nil { - return "[]any" - } - - // Check if items is a reference - itemProxy := schema.Items.A - if itemProxy.IsReference() { - ref := itemProxy.GetReference() - // Check for external reference first - if !strings.HasPrefix(ref, "#") && strings.Contains(ref, "#") { - // External reference - use import mapping - tempDesc := &SchemaDescriptor{Ref: ref} - itemType := g.externalRefType(tempDesc) - return "[]" + itemType - } - // Internal reference - look up in schema index - if target, ok := g.schemaIndex[ref]; ok { - return "[]" + target.ShortName - } - } - - // Check if we have a descriptor for the items schema - if desc != nil && desc.Items != nil && desc.Items.ShortName != "" { - return "[]" + desc.Items.ShortName - } - - // Inline items schema - itemSchema := itemProxy.Schema() - itemType := g.goTypeForSchema(itemSchema, nil) - return "[]" + itemType -} - -// stringType returns the Go type for a string schema. -func (g *TypeGenerator) stringType(schema *base.Schema) string { - spec := g.typeMapping.String.Default - if schema.Format != "" { - if formatSpec, ok := g.typeMapping.String.Formats[schema.Format]; ok { - spec = formatSpec - } - } - - g.AddImport(spec.Import) - g.addTemplate(spec.Template) - return spec.Type -} - -// integerType returns the Go type for an integer schema. -func (g *TypeGenerator) integerType(schema *base.Schema) string { - spec := g.typeMapping.Integer.Default - if schema.Format != "" { - if formatSpec, ok := g.typeMapping.Integer.Formats[schema.Format]; ok { - spec = formatSpec - } - } - - g.AddImport(spec.Import) - return spec.Type -} - -// numberType returns the Go type for a number schema. -func (g *TypeGenerator) numberType(schema *base.Schema) string { - spec := g.typeMapping.Number.Default - if schema.Format != "" { - if formatSpec, ok := g.typeMapping.Number.Formats[schema.Format]; ok { - spec = formatSpec - } - } - - g.AddImport(spec.Import) - return spec.Type -} - -// booleanType returns the Go type for a boolean schema. -func (g *TypeGenerator) booleanType(schema *base.Schema) string { - spec := g.typeMapping.Boolean.Default - g.AddImport(spec.Import) - return spec.Type -} - -// allOfType returns the type name for an allOf composition. -// allOf is typically used for struct embedding/inheritance. -func (g *TypeGenerator) allOfType(desc *SchemaDescriptor) string { - if desc != nil && desc.ShortName != "" { - return desc.ShortName - } - return "any" -} - -// anyOfType returns the type name for an anyOf composition. -func (g *TypeGenerator) anyOfType(desc *SchemaDescriptor) string { - if desc != nil && desc.ShortName != "" { - return desc.ShortName - } - return "any" -} - -// oneOfType returns the type name for a oneOf composition. -func (g *TypeGenerator) oneOfType(desc *SchemaDescriptor) string { - if desc != nil && desc.ShortName != "" { - return desc.ShortName - } - return "any" -} - -// StructField represents a field in a generated Go struct. -type StructField struct { - Name string // Go field name - Type string // Go type expression - JSONName string // Original JSON property name - Required bool // Is this field required in the schema - Nullable bool // Is this field nullable (type includes "null") - Pointer bool // Should this be a pointer type - OmitEmpty bool // Include omitempty in json tag - OmitZero bool // Include omitzero in json tag (Go 1.24+) - JSONIgnore bool // Use json:"-" tag to exclude from marshaling - Doc string // Field documentation - Default string // Go literal for default value (empty if no default) - IsStruct bool // True if this field is a struct type (for recursive ApplyDefaults) - IsNullableAlias bool // True if type is a type alias to Nullable[T] (don't wrap or pointer) - Order *int // Optional field ordering (lower values come first) -} - -// GenerateStructFields creates the list of struct fields for an object schema. -func (g *TypeGenerator) GenerateStructFields(desc *SchemaDescriptor) []StructField { - schema := desc.Schema - if schema == nil || schema.Properties == nil { - return nil - } - - // Build required set - required := make(map[string]bool) - for _, r := range schema.Required { - required[r] = true - } - - var fields []StructField - needsNullableImport := false - - for pair := schema.Properties.First(); pair != nil; pair = pair.Next() { - propName := pair.Key() - propProxy := pair.Value() - - field := StructField{ - Name: g.converter.ToPropertyName(propName), - JSONName: propName, - Required: required[propName], - } - - // Parse extensions from the property schema - var propExtensions *Extensions - var propSchema *base.Schema - - // Resolve the property schema - var propType string - if propProxy.IsReference() { - ref := propProxy.GetReference() - // Check if this is an external reference - if !strings.HasPrefix(ref, "#") && strings.Contains(ref, "#") { - // External reference - use import mapping - tempDesc := &SchemaDescriptor{Ref: ref} - propType = g.externalRefType(tempDesc) - field.IsStruct = true // external references are typically to struct types - } else if target, ok := g.schemaIndex[ref]; ok { - propType = target.ShortName - // Only set IsStruct if the referenced schema has ApplyDefaults - // This filters out array/map type aliases which don't have ApplyDefaults - field.IsStruct = schemaHasApplyDefaults(target.Schema) - // Check if the referenced schema is nullable - // BUT: if it's a nullable primitive, the type alias already wraps Nullable[T], - // so we shouldn't double-wrap it or add a pointer (Nullable handles "unspecified") - if isNullablePrimitive(target.Schema) { - // Already Nullable[T] - use as value type directly - field.IsNullableAlias = true - } else if isNullable(target.Schema) { - field.Nullable = true - } - // Extensions from referenced schema apply to the field - propExtensions = target.Extensions - } else { - propType = "any" - } - } else { - propSchema = propProxy.Schema() - field.Nullable = isNullable(propSchema) - field.Doc = extractDescription(propSchema) - - // Parse extensions from the property schema - if propSchema != nil && propSchema.Extensions != nil { - ext, err := ParseExtensions(propSchema.Extensions, desc.Path.Append("properties", propName).String()) - if err == nil { - propExtensions = ext - } - } - - // Generate the Go type for this property - // Always use goTypeForSchema to get the correct type expression - // This handles arrays, maps, and primitive types correctly - propType = g.goTypeForSchema(propSchema, desc.Properties[propName]) - - // Check if this is a struct type (object with properties, or a named type) - if propSchema != nil { - if propSchema.Properties != nil && propSchema.Properties.Len() > 0 { - field.IsStruct = true - } - // Extract default value - if propSchema.Default != nil { - field.Default = formatDefaultValue(propSchema.Default.Value, propType) - } - } - } - - // Apply extensions to the field - if propExtensions != nil { - // Name override - if propExtensions.NameOverride != "" { - field.Name = propExtensions.NameOverride - } - - // Type override replaces the generated type entirely - if propExtensions.TypeOverride != nil { - propType = propExtensions.TypeOverride.TypeName - if propExtensions.TypeOverride.ImportPath != "" { - if propExtensions.TypeOverride.ImportAlias != "" { - g.AddImportAlias(propExtensions.TypeOverride.ImportPath, propExtensions.TypeOverride.ImportAlias) - } else { - g.AddImport(propExtensions.TypeOverride.ImportPath) - } - } - // Type override bypasses nullable wrapping - the user specifies the exact type - field.IsNullableAlias = true // Don't wrap or add pointer - } - - // JSON ignore - if propExtensions.JSONIgnore != nil && *propExtensions.JSONIgnore { - field.JSONIgnore = true - } - - // Deprecated reason appended to documentation - if propExtensions.DeprecatedReason != "" { - if field.Doc != "" { - field.Doc = field.Doc + "\nDeprecated: " + propExtensions.DeprecatedReason - } else { - field.Doc = "Deprecated: " + propExtensions.DeprecatedReason - } - } - - // Order for field sorting - if propExtensions.Order != nil { - field.Order = propExtensions.Order - } - } - - // Determine type semantics: - // - Nullable fields: use Nullable[T] - // - Optional (not nullable) fields: use *T (pointer) - // - Required (not nullable) fields: use T (value type) - // - Collections (slices/maps) are never wrapped - // - Types already wrapped in Nullable[] are not double-wrapped - // - Type aliases to Nullable[T] are used as-is (IsNullableAlias) - isCollection := strings.HasPrefix(propType, "[]") || strings.HasPrefix(propType, "map[") - alreadyNullable := strings.HasPrefix(propType, "Nullable[") || field.IsNullableAlias - - if field.Nullable && !isCollection && !alreadyNullable { - // Use Nullable[T] for nullable fields (generated inline from template) - field.Type = "Nullable[" + propType + "]" - field.Pointer = false - needsNullableImport = true - } else if !field.Required && !isCollection && !alreadyNullable { - // Check for skip optional pointer extension - skipPointer := false - if propExtensions != nil && propExtensions.SkipOptionalPointer != nil && *propExtensions.SkipOptionalPointer { - skipPointer = true - } - - if skipPointer { - // Use value type even though optional - field.Type = propType - field.Pointer = false - } else { - // Use pointer for optional non-nullable fields - field.Type = "*" + propType - field.Pointer = true - } - } else { - // Value type for required non-nullable fields, collections, and Nullable aliases - field.Type = propType - field.Pointer = false - } - - // Determine omitempty/omitzero behavior - field.OmitEmpty = !field.Required - if propExtensions != nil { - // Explicit omitempty override - if propExtensions.OmitEmpty != nil { - field.OmitEmpty = *propExtensions.OmitEmpty - } - // Explicit omitzero - if propExtensions.OmitZero != nil && *propExtensions.OmitZero { - field.OmitZero = true - } - } - - fields = append(fields, field) - } - - if needsNullableImport { - g.AddNullableTemplate() - } - - // Sort fields by order if any have explicit ordering - sortFieldsByOrder(fields) - - return fields -} - -// collectFieldsRecursive returns the struct fields for a schema, recursively -// following allOf chains. For schemas with direct properties (no allOf), this -// falls through to GenerateStructFields. For allOf-composed schemas, it -// collects fields from all allOf members recursively, so that nested allOf -// references (e.g., A: allOf[$ref:B, ...] where B: allOf[$ref:C, ...]) are -// properly flattened. -func (g *TypeGenerator) collectFieldsRecursive(desc *SchemaDescriptor) []StructField { - schema := desc.Schema - if schema == nil { - return nil - } - - // If this schema has no allOf, use the standard field generation - if len(schema.AllOf) == 0 { - return g.GenerateStructFields(desc) - } - - // Collect fields from direct properties first - var fields []StructField - if schema.Properties != nil && schema.Properties.Len() > 0 { - fields = append(fields, g.GenerateStructFields(desc)...) - } - - // Recursively collect fields from each allOf member - for i, proxy := range schema.AllOf { - memberSchema := proxy.Schema() - if memberSchema == nil { - continue - } - - var memberFields []StructField - if proxy.IsReference() { - ref := proxy.GetReference() - if target, ok := g.schemaIndex[ref]; ok { - // Recurse: the target may itself be an allOf composition - memberFields = g.collectFieldsRecursive(target) - } - } else if memberSchema.Properties != nil && memberSchema.Properties.Len() > 0 { - if desc.AllOf != nil && i < len(desc.AllOf) { - memberFields = g.GenerateStructFields(desc.AllOf[i]) - } - } - - // Apply required array from this allOf member to collected fields - if len(memberSchema.Required) > 0 { - reqSet := make(map[string]bool) - for _, r := range memberSchema.Required { - reqSet[r] = true - } - for j := range memberFields { - if reqSet[memberFields[j].JSONName] && !memberFields[j].Required { - memberFields[j].Required = true - memberFields[j].OmitEmpty = false - if !memberFields[j].Nullable && !strings.HasPrefix(memberFields[j].Type, "[]") && !strings.HasPrefix(memberFields[j].Type, "map[") { - memberFields[j].Type = strings.TrimPrefix(memberFields[j].Type, "*") - memberFields[j].Pointer = false - } - } - } - } - - fields = append(fields, memberFields...) - } - - return fields -} - -// isNullable checks if a schema allows null values. -// In OpenAPI 3.1, this is expressed as type: ["string", "null"] -// In OpenAPI 3.0, this is expressed as nullable: true -func isNullable(schema *base.Schema) bool { - if schema == nil { - return false - } - - // OpenAPI 3.1 style: type array includes "null" - for _, t := range schema.Type { - if t == "null" { - return true - } - } - - // OpenAPI 3.0 style: nullable: true - if schema.Nullable != nil && *schema.Nullable { - return true - } - - return false -} - -// extractDescription gets the description from a schema. -func extractDescription(schema *base.Schema) string { - if schema == nil { - return "" - } - return schema.Description -} - -// formatDefaultValue converts an OpenAPI default value to a Go literal. -// goType is used to determine the correct format for the literal. -func formatDefaultValue(value any, goType string) string { - if value == nil { - return "" - } - - // Strip pointer prefix for type matching - baseType := strings.TrimPrefix(goType, "*") - - switch v := value.(type) { - case string: - // Check if the target type is not a string - // YAML/JSON might parse "10" or "true" as strings - switch baseType { - case "int", "int8", "int16", "int32", "int64", - "uint", "uint8", "uint16", "uint32", "uint64": - // Return the string as-is if it looks like a number - return v - case "bool": - // Return the string as-is if it looks like a bool - if v == "true" || v == "false" { - return v - } - case "float32", "float64": - return v - } - // It's actually a string type - quote it - return fmt.Sprintf("%q", v) - case bool: - return fmt.Sprintf("%t", v) - case float64: - // JSON numbers are always float64 - // Check if it's actually an integer - if v == float64(int64(v)) { - // It's a whole number - if strings.HasPrefix(baseType, "int") || strings.HasPrefix(baseType, "uint") { - return fmt.Sprintf("%d", int64(v)) - } - } - return fmt.Sprintf("%v", v) - case int, int64: - return fmt.Sprintf("%d", v) - case []any: - // Arrays - generate a slice literal - // For now, return empty slice if complex - if len(v) == 0 { - return fmt.Sprintf("%s{}", goType) - } - // Complex array defaults would need recursive handling - return "" - case map[string]any: - // Objects - for now, skip complex defaults - if len(v) == 0 { - return fmt.Sprintf("%s{}", goType) - } - return "" - default: - // Try a simple string conversion - return fmt.Sprintf("%v", v) - } -} - -// HasAdditionalProperties returns true if the schema has explicit additionalProperties. -func (g *TypeGenerator) HasAdditionalProperties(desc *SchemaDescriptor) bool { - if desc == nil || desc.Schema == nil { - return false - } - return desc.Schema.AdditionalProperties != nil -} - -// AdditionalPropertiesType returns the Go type for the additionalProperties. -func (g *TypeGenerator) AdditionalPropertiesType(desc *SchemaDescriptor) string { - if desc == nil || desc.Schema == nil || desc.Schema.AdditionalProperties == nil { - return "any" - } - - if desc.Schema.AdditionalProperties.A != nil { - valueSchema := desc.Schema.AdditionalProperties.A.Schema() - if valueSchema != nil { - return g.goTypeForSchema(valueSchema, nil) - } - } - - return "any" -} - -// SchemaKind represents the kind of schema for code generation. -type SchemaKind int - -const ( - KindStruct SchemaKind = iota - KindMap - KindAlias - KindEnum - KindAllOf - KindAnyOf - KindOneOf - KindReference -) - -// GetSchemaKind determines what kind of Go type to generate for a schema. -func GetSchemaKind(desc *SchemaDescriptor) SchemaKind { - if desc.IsReference() { - return KindReference - } - - schema := desc.Schema - if schema == nil { - return KindAlias - } - - // Enum check first - if len(schema.Enum) > 0 { - return KindEnum - } - - // Composition types - if len(schema.AllOf) > 0 { - return KindAllOf - } - if len(schema.AnyOf) > 0 { - return KindAnyOf - } - if len(schema.OneOf) > 0 { - return KindOneOf - } - - // Object with properties -> struct - if schema.Properties != nil && schema.Properties.Len() > 0 { - return KindStruct - } - - // Object with only additionalProperties -> map - primaryType := getPrimaryType(schema) - if primaryType == "object" { - if schema.AdditionalProperties != nil { - return KindMap - } - return KindStruct // empty struct - } - - // Everything else is an alias to a primitive type - return KindAlias -} - -// FormatJSONTag generates a JSON struct tag for a field. -// Deprecated: Use StructTagGenerator instead. -func FormatJSONTag(jsonName string, omitEmpty bool) string { - if omitEmpty { - return fmt.Sprintf("`json:\"%s,omitempty\"`", jsonName) - } - return fmt.Sprintf("`json:\"%s\"`", jsonName) -} - -// GenerateFieldTag generates struct tags for a field using the configured templates. -func (g *TypeGenerator) GenerateFieldTag(field StructField) string { - if g.tagGenerator == nil { - // Fallback to legacy behavior - if field.JSONIgnore { - return "`json:\"-\"`" - } - return FormatJSONTag(field.JSONName, field.OmitEmpty) - } - - info := StructTagInfo{ - FieldName: field.JSONName, - GoFieldName: field.Name, - IsOptional: !field.Required, - IsNullable: field.Nullable, - IsPointer: field.Pointer, - OmitEmpty: field.OmitEmpty, - OmitZero: field.OmitZero, - JSONIgnore: field.JSONIgnore, - } - return g.tagGenerator.GenerateTags(info) -} - -// TagGenerator returns the struct tag generator. -func (g *TypeGenerator) TagGenerator() *StructTagGenerator { - return g.tagGenerator -} - -// sortFieldsByOrder sorts fields by their Order value. -// Fields without an Order value are placed after fields with explicit ordering, -// maintaining their original relative order (stable sort). -func sortFieldsByOrder(fields []StructField) { - // Check if any fields have explicit ordering - hasOrder := false - for _, f := range fields { - if f.Order != nil { - hasOrder = true - break - } - } - if !hasOrder { - return - } - - // Stable sort to preserve relative order of fields without explicit ordering - sort.SliceStable(fields, func(i, j int) bool { - // Fields with Order come before fields without - if fields[i].Order == nil && fields[j].Order == nil { - return false // preserve original order - } - if fields[i].Order == nil { - return false // i (no order) comes after j - } - if fields[j].Order == nil { - return true // i (has order) comes before j - } - // Both have order - sort by value - return *fields[i].Order < *fields[j].Order - }) -} diff --git a/experimental/internal/codegen/typemapping.go b/experimental/internal/codegen/typemapping.go deleted file mode 100644 index 235b06260f..0000000000 --- a/experimental/internal/codegen/typemapping.go +++ /dev/null @@ -1,98 +0,0 @@ -package codegen - -// SimpleTypeSpec is used to define the Go typename of a simple type like -// an int or a string, along with the import required to use it. -type SimpleTypeSpec struct { - Type string `yaml:"type"` - Import string `yaml:"import,omitempty"` - Template string `yaml:"template,omitempty"` -} - -// FormatMapping defines the default Go type and format-specific overrides. -type FormatMapping struct { - Default SimpleTypeSpec `yaml:"default"` - Formats map[string]SimpleTypeSpec `yaml:"formats,omitempty"` -} - -// TypeMapping defines the mapping from OpenAPI types to Go types. -type TypeMapping struct { - Integer FormatMapping `yaml:"integer,omitempty"` - Number FormatMapping `yaml:"number,omitempty"` - Boolean FormatMapping `yaml:"boolean,omitempty"` - String FormatMapping `yaml:"string,omitempty"` -} - -// 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 - for k, v := range base.Formats { - result.Formats[k] = v - } - - // Override with user default if specified - if user.Default.Type != "" { - result.Default = user.Default - } - - // Override/add user formats - for k, v := range user.Formats { - result.Formats[k] = v - } - - return result -} - -// 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: "Email", Template: "email.tmpl"}, - "date": {Type: "Date", Template: "date.tmpl"}, - "date-time": {Type: "time.Time", Import: "time"}, - "json": {Type: "json.RawMessage", Import: "encoding/json"}, - "uuid": {Type: "UUID", Template: "uuid.tmpl"}, - "binary": {Type: "File", Template: "file.tmpl"}, - }, - }, -} diff --git a/experimental/internal/codegen/typenames.go b/experimental/internal/codegen/typenames.go deleted file mode 100644 index c4d47b51af..0000000000 --- a/experimental/internal/codegen/typenames.go +++ /dev/null @@ -1 +0,0 @@ -package codegen diff --git a/scripts/foreach-module.sh b/scripts/foreach-module.sh deleted file mode 100755 index 7addae7825..0000000000 --- a/scripts/foreach-module.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Run a make target in each child go module whose go directive is compatible -# with the current Go toolchain. Modules requiring a newer Go are skipped. -# -# Usage: foreach-module.sh -set -euo pipefail - -target="${1:?usage: foreach-module.sh }" -cur_go="$(go env GOVERSION | sed 's/^go//')" - -git ls-files '**/*go.mod' -z | while IFS= read -r -d '' modfile; do - mod_go="$(sed -n 's/^go *//p' "$modfile")" - moddir="$(dirname "$modfile")" - - if [ "$(printf '%s\n%s' "$mod_go" "$cur_go" | sort -V | head -1)" = "$mod_go" ]; then - (set -x; cd "$moddir" && env GOBIN="${GOBIN:-}" make "$target") - else - echo "Skipping $moddir: requires go $mod_go, have go $cur_go" - fi -done From 35a6e0c76d169aafd1a1f3b8a6ef0f1b17c0ab8d Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 7 Feb 2026 12:49:12 +0000 Subject: [PATCH 158/293] build: use a re-usable, single, workflow for running CI As a way to keep updates to the CI pipelines more straightforward, we can extract this out to a shared, versioned (and updated by Renovate) Action. We can make sure to keep our binary builds going, but only for the current versions of Go - other build failures will be caught by our shared Action. --- .github/workflows/ci.yml | 43 +++++++++-------------------- .github/workflows/generate.yml | 50 ---------------------------------- .github/workflows/lint.yml | 47 -------------------------------- .github/workflows/tidy.yml | 50 ---------------------------------- 4 files changed, 13 insertions(+), 177 deletions(-) delete mode 100644 .github/workflows/generate.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/tidy.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eeb0208241..7a7d578881 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,22 +1,22 @@ -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@b9f2c274c1c631e648931dbbcc1942c2b2027837 # v0.4.0 + + 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.22" - - "1.23" - - "1.24" - - "1.25" + - "stable" + - "oldstable" steps: - name: Check out source code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -26,25 +26,8 @@ jobs: 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 - - results: - if: ${{ always() }} - runs-on: ubuntu-latest - name: Check build results - needs: [build] - steps: - - run: | - result="${{ needs.build.result }}" - if [[ $result == "success" || $result == "skipped" ]]; then - exit 0 - else - exit 1 - fi diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml deleted file mode 100644 index 4a0e5db377..0000000000 --- a/.github/workflows/generate.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Ensure generated files are up-to-date -on: [ push, pull_request ] - -permissions: - contents: read - -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.22" - - "1.23" - - "1.24" - - "1.25" - steps: - - name: Check out source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Set up Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - 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 -- - - results: - if: ${{ always() }} - runs-on: ubuntu-latest - name: Check generation results - needs: [build] - steps: - - run: | - result="${{ needs.build.result }}" - if [[ $result == "success" || $result == "skipped" ]]; then - exit 0 - else - exit 1 - fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 8246442b1e..0000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Lint project -on: [push, pull_request] - -permissions: - contents: read - -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.22" - - "1.23" - - "1.24" - - "1.25" - steps: - - name: Check out source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Set up Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - 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 - - results: - if: ${{ always() }} - runs-on: ubuntu-latest - name: Check linting results - needs: [build] - steps: - - run: | - result="${{ needs.build.result }}" - if [[ $result == "success" || $result == "skipped" ]]; then - exit 0 - else - exit 1 - fi diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml deleted file mode 100644 index 4d5e66a992..0000000000 --- a/.github/workflows/tidy.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Ensure `go mod tidy` has been run -on: [ push, pull_request ] - -permissions: - contents: read - -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.22" - - "1.23" - - "1.24" - - "1.25" - steps: - - name: Check out source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Set up Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 - 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 - - results: - if: ${{ always() }} - runs-on: ubuntu-latest - name: Check tidy results - needs: [build] - steps: - - run: | - result="${{ needs.build.result }}" - if [[ $result == "success" || $result == "skipped" ]]; then - exit 0 - else - exit 1 - fi From bae5e574935f19c744ac71766fc16a7312fab4bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:41:04 -0800 Subject: [PATCH 159/293] fix(deps): update module github.com/gofiber/fiber/v2 to v2.52.11 [security] (#2207) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- examples/go.mod | 12 ++++++------ examples/go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 7c9b783567..c3aa80b848 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -8,8 +8,8 @@ require ( github.com/getkin/kin-openapi v0.133.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/gofiber/fiber/v2 v2.52.11 + 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 @@ -32,7 +32,7 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // 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 @@ -64,7 +64,7 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -77,7 +77,7 @@ require ( 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/mattn/go-runewidth v0.0.16 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -112,7 +112,7 @@ require ( golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.25.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 97e7e8ae43..a28b5aa86a 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -13,8 +13,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 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= @@ -79,8 +79,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= 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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -106,8 +106,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD 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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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/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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -139,8 +139,8 @@ 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/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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= @@ -180,8 +180,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk 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/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -379,8 +379,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.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= From 2ec5a320dab48900f092cb26c59d17d781aaf5c3 Mon Sep 17 00:00:00 2001 From: Yuichiro Tsuji Date: Tue, 10 Feb 2026 07:23:23 +0900 Subject: [PATCH 160/293] docs(extensions): correct links to examples (#1836) Co-authored-by: Yuichiro Tsuji From 54868c73f060f46a64c55346ee5aa6cc1497f0eb Mon Sep 17 00:00:00 2001 From: Richard Kosegi Date: Mon, 9 Feb 2026 23:31:24 +0100 Subject: [PATCH 161/293] docs: fix link to example (#1884) Signed-off-by: Richard Kosegi Co-authored-by: Marcin Romaszewicz From 61057963748a269c3d082146b6cd49aef522a9f7 Mon Sep 17 00:00:00 2001 From: Ula <46541238+ula@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:32:16 -0500 Subject: [PATCH 162/293] Fixes type collision for enum values that start with _ (underscore) (#1438) Co-authored-by: Ula Co-authored-by: Marcin Romaszewicz --- pkg/codegen/utils_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index af71438473..0666fc9909 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -604,6 +604,7 @@ func TestSchemaNameToTypeName(t *testing.T) { "=3": "Equal3", "#Tag": "HashTag", ".com": "DotCom", + "_1": "Underscore1", ">=": "GreaterThanEqual", "<=": "LessThanEqual", "<": "LessThan", From e8ada7a95863f9b630aaa839c66a12735113498c Mon Sep 17 00:00:00 2001 From: ShouheiNishi <96609867+ShouheiNishi@users.noreply.github.com> Date: Tue, 10 Feb 2026 07:34:12 +0900 Subject: [PATCH 163/293] Fix broken code when response content is not exist, but response headers are exist in Iris strict server. (#1411) Co-authored-by: Marcin Romaszewicz --- pkg/codegen/templates/strict/strict-iris-interface.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index e93fdf6166..5ebbc4e1b3 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -128,7 +128,7 @@ {{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}})) + ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) {{end -}} ctx.StatusCode({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) return nil From 5bde24dc8f18713a0dad0ea24657289f0c5c9b9f Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 9 Feb 2026 20:27:26 -0800 Subject: [PATCH 164/293] chore: readme update (#2209) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7bac0d2e98..a81ccc92d1 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,8 @@ We can see that this provides the best means to focus on the implementation of t - Support multiple OpenAPI files by having a package-per-OpenAPI file - Support of OpenAPI 3.0 - OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373) + However, we do have an experimental version using a different OpenAPI parser which does support 3.1 and 3.2, which + you can play around with in our [experimental repo](https://github.com/oapi-codegen/oapi-codegen-exp/tree/main/experimental) - Note that this does not include OpenAPI 2.0 (aka Swagger) - Extract parameters from requests, to reduce work required by your implementation - Implicit `additionalProperties` are ignored by default ([more details](#additional-properties-additionalproperties)) From 5f38641c2bea522153b04d95069629489cf20cfb Mon Sep 17 00:00:00 2001 From: Alexey Boltunov <42418759+getBolted@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:11:17 +0200 Subject: [PATCH 165/293] Adopt fiber middleware template for updated GetReqHeaders() method signature (#1419) * hotfix: - Bump fiber version to 2.52.0 - Adopted middleware template for fiber to handle new GetReqHeader() method, that has changed signature in fiber 2.50.0 (https://github.com/gofiber/fiber/releases/tag/v2.50.0) * Use latest fiber, and fix go deps The latest Fiber requires Go 1.24, therefore, we have to increase the version in the modules which use it. This is constrained to tests and examples, so it doesn't affect the main repo. Go 1.24 can't compile the version of golang.org/x/tools which we were using, so update that as well. * fix: use valueList[0] for fiber header IsPassThrough case The merge with upstream/main resolved a conflict in the fiber middleware template's header IsPassThrough handler by taking upstream's version, which still used the old single-string `value` variable. This is incorrect because fiber 2.50.0+ changed GetReqHeaders() to return map[string][]string. Fix by using valueList[0] to match the rest of the header handling block. Co-Authored-By: Claude Opus 4.6 * Tidy up modules This seems to be about the minimal set of changes to have everything build and test cleanly. * fix: add Go 1.24 version guards to Makefiles The internal/test and examples modules now require Go 1.24+ in their go.mod files, but their Makefiles lacked version guards, causing CI failures on Go 1.22 and 1.23. Add execute-if-go-124 guards matching the pattern used by other Go 1.24+ modules. Also bump the strict-server/stdhttp Makefile guard from 1.22 to 1.24. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Alexey Boltunov Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- examples/Makefile | 31 ++++++-- examples/authenticated-api/stdhttp/go.mod | 6 +- examples/authenticated-api/stdhttp/go.sum | 22 +++--- examples/extensions/xomitzero/go.mod | 6 +- examples/extensions/xomitzero/go.sum | 22 +++--- examples/go.mod | 29 ++++---- examples/go.sum | 59 ++++++++------- .../minimal-server/stdhttp-go-tool/go.mod | 6 +- .../minimal-server/stdhttp-go-tool/go.sum | 22 +++--- examples/minimal-server/stdhttp/go.mod | 6 +- examples/minimal-server/stdhttp/go.sum | 22 +++--- .../go.mod | 6 +- .../go.sum | 22 +++--- examples/petstore-expanded/stdhttp/go.mod | 6 +- examples/petstore-expanded/stdhttp/go.sum | 22 +++--- go.mod | 6 +- go.sum | 22 +++--- internal/test/Makefile | 31 ++++++-- internal/test/go.mod | 35 +++++---- internal/test/go.sum | 71 +++++++++---------- .../test/strict-server/fiber/server.gen.go | 16 +++-- internal/test/strict-server/stdhttp/Makefile | 18 ++--- internal/test/strict-server/stdhttp/go.mod | 12 ++-- internal/test/strict-server/stdhttp/go.sum | 30 ++++---- .../templates/fiber/fiber-middleware.tmpl | 12 ++-- 25 files changed, 299 insertions(+), 241 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 5ec0edd058..bb37d63394 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,17 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + lint: - $(GOBIN)/golangci-lint run ./... + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: - go generate ./... + $(call execute-if-go-124,go generate ./...) test: - go test -cover ./... + $(call execute-if-go-124,go test -cover ./...) tidy: - go mod tidy + $(call execute-if-go-124,go mod tidy) tidy-ci: - tidied -verbose + $(call execute-if-go-124,tidied -verbose) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 2ca2945993..3a2081ba2a 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -39,10 +39,10 @@ require ( github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.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 index d38b743f8d..a6e130e447 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -37,6 +37,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= @@ -137,8 +139,8 @@ golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -151,15 +153,15 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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-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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -180,8 +182,8 @@ 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/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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= @@ -202,8 +204,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod index e7b7295e3e..6b1e3678b8 100644 --- a/examples/extensions/xomitzero/go.mod +++ b/examples/extensions/xomitzero/go.mod @@ -26,10 +26,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum index 2319ae885e..fdce2066b1 100644 --- a/examples/extensions/xomitzero/go.sum +++ b/examples/extensions/xomitzero/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -95,8 +97,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -104,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -125,8 +127,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -138,8 +140,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/go.mod b/examples/go.mod index c3aa80b848..011b9ad67a 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.22.5 +go 1.24.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ @@ -32,11 +32,12 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.1.0 // indirect + github.com/andybalholm/brotli v1.2.0 // 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/clipperhouse/uax29/v2 v2.6.0 // 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 @@ -64,7 +65,7 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -75,9 +76,9 @@ require ( github.com/lestrrat-go/option v1.0.1 // 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-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -88,7 +89,6 @@ require ( 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/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect @@ -99,23 +99,22 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.39.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 diff --git a/examples/go.sum b/examples/go.sum index a28b5aa86a..0f5c1ca023 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -13,8 +13,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/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= @@ -27,6 +27,8 @@ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4 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.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= +github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 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= @@ -139,8 +141,8 @@ 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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= 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= @@ -175,13 +177,12 @@ github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqA 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-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.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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -235,9 +236,6 @@ 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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -284,12 +282,10 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -304,6 +300,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -323,8 +321,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -332,8 +330,8 @@ 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= 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= @@ -347,16 +345,16 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -375,12 +373,11 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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= @@ -391,8 +388,8 @@ 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -402,8 +399,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= 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= diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod index 7c900939fb..de08a03c54 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ b/examples/minimal-server/stdhttp-go-tool/go.mod @@ -22,10 +22,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.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-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum index 2319ae885e..fdce2066b1 100644 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ b/examples/minimal-server/stdhttp-go-tool/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -95,8 +97,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -104,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -125,8 +127,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -138,8 +140,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 9661c9998f..f1ef1ba7b4 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -21,10 +21,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.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 index 2319ae885e..fdce2066b1 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -95,8 +97,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -104,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -125,8 +127,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -138,8 +140,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod index f3b0a6cfe8..6f75dac750 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod @@ -26,10 +26,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum index 2319ae885e..fdce2066b1 100644 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -95,8 +97,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -104,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -125,8 +127,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -138,8 +140,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index c1ef1e0491..536fc339df 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -32,10 +32,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.30.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 index 458fbf7291..7bf494f54d 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -36,6 +36,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -112,8 +114,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -121,13 +123,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -142,8 +144,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -155,8 +157,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/go.mod b/go.mod index 9431a8d978..12e391a6ee 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,9 @@ require ( github.com/getkin/kin-openapi v0.133.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.11.1 - golang.org/x/mod v0.21.0 + golang.org/x/mod v0.23.0 golang.org/x/text v0.20.0 - golang.org/x/tools v0.25.1 + golang.org/x/tools v0.30.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -29,5 +29,5 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/sync v0.9.0 // indirect + golang.org/x/sync v0.11.0 // indirect ) diff --git a/go.sum b/go.sum index 2319ae885e..fdce2066b1 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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= @@ -95,8 +97,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -104,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -125,8 +127,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -138,8 +140,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/internal/test/Makefile b/internal/test/Makefile index 5ec0edd058..bb37d63394 100644 --- a/internal/test/Makefile +++ b/internal/test/Makefile @@ -1,17 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + lint: - $(GOBIN)/golangci-lint run ./... + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: - go generate ./... + $(call execute-if-go-124,go generate ./...) test: - go test -cover ./... + $(call execute-if-go-124,go test -cover ./...) tidy: - go mod tidy + $(call execute-if-go-124,go mod tidy) tidy-ci: - tidied -verbose + $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/go.mod b/internal/test/go.mod index 10ef9b25ed..6d321d86bf 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.22.5 +go 1.24.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ @@ -8,8 +8,8 @@ require ( github.com/getkin/kin-openapi v0.133.0 github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi/v5 v5.0.10 - github.com/gofiber/fiber/v2 v2.49.1 - github.com/google/uuid v1.4.0 + github.com/gofiber/fiber/v2 v2.52.11 + 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 @@ -27,12 +27,13 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.2.0 // 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/clipperhouse/uax29/v2 v2.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -57,15 +58,15 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.18.4 // 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/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/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -75,7 +76,6 @@ require ( 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/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.8.1 // indirect @@ -87,23 +87,22 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.49.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/tools v0.39.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index ca696cc621..336b745da8 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -13,8 +13,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/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= @@ -33,6 +33,8 @@ github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI 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.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= +github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 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= @@ -78,8 +80,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= 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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -105,8 +107,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD 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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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/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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -138,8 +140,8 @@ 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/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= 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= @@ -162,14 +164,13 @@ github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNf 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-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.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/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.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -213,9 +214,6 @@ github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX 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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -263,13 +261,11 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= -github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -284,6 +280,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -300,12 +298,12 @@ golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= 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= @@ -315,14 +313,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -342,27 +340,26 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc 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-20211216021012-1d35b9e2eb4e/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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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/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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= 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= diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index b15d923fd0..edf81be1fb 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -151,10 +151,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}) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error()) } @@ -167,10 +171,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}) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error()) } diff --git a/internal/test/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile index 48fe768e30..bb37d63394 100644 --- a/internal/test/strict-server/stdhttp/Makefile +++ b/internal/test/strict-server/stdhttp/Makefile @@ -6,31 +6,31 @@ RESET := \e[0;0m GOVER := $(shell go env GOVERSION) GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") -define execute-if-go-122 +define execute-if-go-124 @{ \ -if [[ 22 -le $(GOMINOR) ]]; then \ +if [[ 24 -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)"; \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ fi \ } endef lint: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...) + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) lint-ci: - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: - $(call execute-if-go-122,go generate ./...) + $(call execute-if-go-124,go generate ./...) test: - $(call execute-if-go-122,go test -cover ./...) + $(call execute-if-go-124,go test -cover ./...) tidy: - $(call execute-if-go-122,go mod tidy) + $(call execute-if-go-124,go mod tidy) tidy-ci: - $(call execute-if-go-122,tidied -verbose) + $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 5d3c8860d2..cdd0f48f20 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp -go 1.22.5 +go 1.24.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ @@ -21,7 +21,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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/google/uuid v1.6.0 // 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 @@ -33,10 +33,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.25.1 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/tools v0.39.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 index 7fe4b88d07..c5c399b374 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -36,9 +36,11 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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/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/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/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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -108,8 +110,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= 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= @@ -117,13 +119,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -138,21 +140,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.25.1 h1:YeIyhd0M7gStYR9jb2IFXVVT+QJhgXu1ZECOuRwofh4= -golang.org/x/tools v0.25.1/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= 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= diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index e44f4836cb..3213e22a7d 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -89,22 +89,26 @@ 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 .HasOptionalPointer}}&{{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}}}) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) } From 13eb5ac37e1919b8860e9d3a223e468ae1d7ddc8 Mon Sep 17 00:00:00 2001 From: Mehmet Gurevin Date: Tue, 10 Feb 2026 21:22:44 +0300 Subject: [PATCH 166/293] fixed duplicate type names (#200) * fixed duplicate type names * add typename dedup functions * Fixup: use full-word suffixes and add regression test for issue #200 - Rename auto-dedup suffixes to use full words: Parameter, Response, RequestBody (instead of Param, Resp, ReqBody) - Add internal/test/issues/issue-200/ with spec, config, generated code, and a compile-time regression test that instantiates every expected type Co-Authored-By: Claude Opus 4.6 * Gate duplicate type name resolution behind output-options config flag Add ResolveTypeNameCollisions bool to OutputOptions and the JSON schema. When false (the default), the codegen errors on duplicate type names as before. When true, FixDuplicateTypeNames auto-renames colliding types. Also cleans up ComponentType: removes unused constants, improves doc. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- configuration-schema.json | 5 ++ internal/test/issues/issue-200/config.yaml | 7 ++ internal/test/issues/issue-200/doc.go | 3 + .../test/issues/issue-200/issue200.gen.go | 49 +++++++++++ .../test/issues/issue-200/issue200_test.go | 48 +++++++++++ internal/test/issues/issue-200/spec.yaml | 80 ++++++++++++++++++ pkg/codegen/codegen.go | 15 +++- pkg/codegen/configuration.go | 8 ++ pkg/codegen/schema.go | 25 +++++- pkg/codegen/utils.go | 83 +++++++++++++++++++ 10 files changed, 317 insertions(+), 6 deletions(-) create mode 100644 internal/test/issues/issue-200/config.yaml create mode 100644 internal/test/issues/issue-200/doc.go create mode 100644 internal/test/issues/issue-200/issue200.gen.go create mode 100644 internal/test/issues/issue-200/issue200_test.go create mode 100644 internal/test/issues/issue-200/spec.yaml diff --git a/configuration-schema.json b/configuration-schema.json index 9047914479..8ff58d94b6 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -252,6 +252,11 @@ "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 (e.g., 'Parameter', 'Response', 'RequestBody'). Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.", + "default": false } } }, diff --git a/internal/test/issues/issue-200/config.yaml b/internal/test/issues/issue-200/config.yaml new file mode 100644 index 0000000000..d68804c987 --- /dev/null +++ b/internal/test/issues/issue-200/config.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=../../../../configuration-schema.json +package: issue200 +generate: + models: true +output: issue200.gen.go +output-options: + resolve-type-name-collisions: true diff --git a/internal/test/issues/issue-200/doc.go b/internal/test/issues/issue-200/doc.go new file mode 100644 index 0000000000..733ebfce17 --- /dev/null +++ b/internal/test/issues/issue-200/doc.go @@ -0,0 +1,3 @@ +package issue200 + +//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-200/issue200.gen.go b/internal/test/issues/issue-200/issue200.gen.go new file mode 100644 index 0000000000..cc3c138314 --- /dev/null +++ b/internal/test/issues/issue-200/issue200.gen.go @@ -0,0 +1,49 @@ +// Package issue200 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 issue200 + +// 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"` +} + +// BarParam defines model for BarParam. +type BarParam = []int + +// BarParam2 defines model for BarParam2. +type BarParam2 = []int + +// BarParameter defines model for Bar. +type BarParameter = string + +// BarResponse defines model for Bar. +type BarResponse struct { + Value1 *Bar `json:"value1,omitempty"` + Value2 *Bar2 `json:"value2,omitempty"` + Value3 *BarParam `json:"value3,omitempty"` + Value4 *BarParam2 `json:"value4,omitempty"` +} + +// BarRequestBody defines model for Bar. +type BarRequestBody struct { + Value *int `json:"value,omitempty"` +} + +// PostFooJSONBody defines parameters for PostFoo. +type PostFooJSONBody struct { + Value *int `json:"value,omitempty"` +} + +// PostFooParams defines parameters for PostFoo. +type PostFooParams struct { + Bar *Bar `form:"Bar,omitempty" json:"Bar,omitempty"` +} + +// PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. +type PostFooJSONRequestBody PostFooJSONBody diff --git a/internal/test/issues/issue-200/issue200_test.go b/internal/test/issues/issue-200/issue200_test.go new file mode 100644 index 0000000000..9f690d520c --- /dev/null +++ b/internal/test/issues/issue-200/issue200_test.go @@ -0,0 +1,48 @@ +package issue200 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestDuplicateTypeNamesCompile verifies that when the same name "Bar" is used +// across components/schemas, components/parameters, components/responses, +// components/requestBodies, and components/headers, the codegen produces +// distinct, compilable types with component-based suffixes. +// +// If the auto-rename logic breaks, this test will fail to compile. +func TestDuplicateTypeNamesCompile(t *testing.T) { + // Schema type: Bar (no suffix, first definition wins) + _ = Bar{Value: ptr("hello")} + + // Schema types with unique names (no collision) + _ = Bar2{Value: ptr(float32(1.0))} + _ = BarParam([]int{1, 2, 3}) + _ = BarParam2([]int{4, 5, 6}) + + // Parameter type: BarParameter (was "Bar" in components/parameters) + _ = BarParameter("query-value") + + // Response type: BarResponse (was "Bar" in components/responses) + _ = BarResponse{ + Value1: &Bar{Value: ptr("v1")}, + Value2: &Bar2{Value: ptr(float32(2.0))}, + Value3: &BarParam{1}, + Value4: &BarParam2{2}, + } + + // RequestBody type: BarRequestBody (was "Bar" in components/requestBodies) + _ = BarRequestBody{Value: ptr(42)} + + // Operation-derived types + _ = PostFooParams{Bar: &Bar{}} + _ = PostFooJSONBody{Value: ptr(99)} + _ = PostFooJSONRequestBody{Value: ptr(100)} + + assert.True(t, true, "all duplicate-named types resolved and compiled") +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/internal/test/issues/issue-200/spec.yaml b/internal/test/issues/issue-200/spec.yaml new file mode 100644 index 0000000000..a18c7f403c --- /dev/null +++ b/internal/test/issues/issue-200/spec.yaml @@ -0,0 +1,80 @@ +openapi: 3.0.1 + +info: + title: "Duplicate type names test" + version: 0.0.0 + +paths: + /foo: + post: + operationId: postFoo + parameters: + - $ref: '#/components/parameters/Bar' + requestBody: + $ref: '#/components/requestBodies/Bar' + responses: + 200: + $ref: '#/components/responses/Bar' + +components: + schemas: + Bar: + type: object + properties: + value: + type: string + Bar2: + type: object + properties: + value: + type: number + BarParam: + type: array + items: + type: integer + BarParam2: + type: array + items: + type: integer + + headers: + Bar: + schema: + type: boolean + + parameters: + Bar: + name: Bar + in: query + schema: + type: string + + requestBodies: + Bar: + content: + application/json: + schema: + type: object + properties: + value: + type: integer + + 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' + value3: + $ref: '#/components/schemas/BarParam' + value4: + $ref: '#/components/schemas/BarParam2' diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 04ac96cc66..279ed9d081 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -673,6 +673,8 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response return nil, fmt.Errorf("error making name for components/responses/%s: %w", responseName, err) } + goType.DefinedComp = ComponentTypeResponse + typeDef := TypeDefinition{ JsonName: responseName, Schema: goType, @@ -724,6 +726,8 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open return nil, fmt.Errorf("error making name for components/schemas/%s: %w", requestBodyName, err) } + goType.DefinedComp = ComponentTypeRequestBody + typeDef := TypeDefinition{ JsonName: requestBodyName, Schema: goType, @@ -750,15 +754,18 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) m := map[string]TypeDefinition{} var ts []TypeDefinition + if globalState.options.OutputOptions.ResolveTypeNameCollisions { + types = FixDuplicateTypeNames(types) + } + 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. + // If type names collide after auto-rename, 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. 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) } diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 1d9ff3eaea..d3281fefec 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -300,6 +300,14 @@ type OutputOptions struct { // 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"). 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"` } func (oo OutputOptions) Validate() map[string]string { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index c099752d88..7435fa224d 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -39,8 +39,22 @@ type Schema struct { // The original OpenAPIv3 Schema. OAPISchema *openapi3.Schema + + DefinedComp ComponentType // Indicates which component section defined this type } +// ComponentType is used to keep track of where a given schema came from, in order +// to perform type name collision resolution. +type ComponentType int + +const ( + ComponentTypeSchema = iota + ComponentTypeParameter + ComponentTypeRequestBody + ComponentTypeResponse + ComponentTypeHeader +) + func (s Schema) IsRef() bool { return s.RefType != "" } @@ -311,6 +325,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { Description: schema.Description, OAPISchema: schema, SkipOptionalPointer: skipOptionalPointer, + DefinedComp: ComponentTypeSchema, } // AllOf is interesting, and useful. It's the union of a number of other @@ -849,7 +864,9 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { // We can process the schema through the generic schema processor if param.Schema != nil { - return GenerateGoSchema(param.Schema, path) + schema, err := GenerateGoSchema(param.Schema, path) + schema.DefinedComp = ComponentTypeParameter + return schema, err } // At this point, we have a content type. We know how to deal with @@ -859,6 +876,7 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), + DefinedComp: ComponentTypeParameter, }, nil } @@ -869,11 +887,14 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), + DefinedComp: ComponentTypeParameter, }, nil } // For json, we go through the standard schema mechanism - return GenerateGoSchema(mt.Schema, path) + schema, err := GenerateGoSchema(mt.Schema, path) + schema.DefinedComp = ComponentTypeParameter + return schema, err } func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminator *openapi3.Discriminator, path []string) error { diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 5326e672bf..691d887663 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -1112,3 +1112,86 @@ func sliceContains[E comparable](s []E, v E) bool { } return false } + +// FixDuplicateTypeNames renames duplicate type names. +func FixDuplicateTypeNames(typeDefs []TypeDefinition) []TypeDefinition { + if !hasDuplicatedTypeNames(typeDefs) { + return typeDefs + } + + // try to fix duplicate type names with their definition section + typeDefs = fixDuplicateTypeNamesWithCompName(typeDefs) + if !hasDuplicatedTypeNames(typeDefs) { + return typeDefs + } + + const maxIter = 100 + for i := 0; i < maxIter && hasDuplicatedTypeNames(typeDefs); i++ { + typeDefs = fixDuplicateTypeNamesDupCounts(typeDefs) + } + + if hasDuplicatedTypeNames(typeDefs) { + panic("too much duplicate type names") + } + + return typeDefs +} + +func hasDuplicatedTypeNames(typeDefs []TypeDefinition) bool { + dupCheck := make(map[string]int, len(typeDefs)) + + for _, d := range typeDefs { + dupCheck[d.TypeName]++ + + if dupCheck[d.TypeName] != 1 { + return true + } + } + + return false +} + +func fixDuplicateTypeNamesWithCompName(typeDefs []TypeDefinition) []TypeDefinition { + dupCheck := make(map[string]int, len(typeDefs)) + deDup := make([]TypeDefinition, len(typeDefs)) + + for i, d := range typeDefs { + dupCheck[d.TypeName]++ + + if dupCheck[d.TypeName] != 1 { + switch d.Schema.DefinedComp { + case ComponentTypeSchema: + d.TypeName += "Schema" + case ComponentTypeParameter: + d.TypeName += "Parameter" + case ComponentTypeRequestBody: + d.TypeName += "RequestBody" + case ComponentTypeResponse: + d.TypeName += "Response" + case ComponentTypeHeader: + d.TypeName += "Header" + } + } + + deDup[i] = d + } + + return deDup +} + +func fixDuplicateTypeNamesDupCounts(typeDefs []TypeDefinition) []TypeDefinition { + dupCheck := make(map[string]int, len(typeDefs)) + deDup := make([]TypeDefinition, len(typeDefs)) + + for i, d := range typeDefs { + dupCheck[d.TypeName]++ + + if dupCheck[d.TypeName] != 1 { + d.TypeName = d.TypeName + strconv.Itoa(dupCheck[d.TypeName]) + } + + deDup[i] = d + } + + return deDup +} From 15c1dafe763ea2cfc0b9be0c136a79fb33bca2d6 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 11 Feb 2026 20:53:30 -0800 Subject: [PATCH 167/293] refactor(internal): move Fiber tests into their own modules (#2212) * Fiber deps in their own modules Move the fiber dependences to their own modules, to contain Go 1.24 to the minimal subset of our code. Update make rules to exclude Go 1.24 tests on Go < 1.24 Update Readme with minimum Go version for each router. * Update Fiber in test issue Contain Fiber to its own module in test for Issue 1469 --- README.md | 28 ++- examples/Makefile | 31 +-- examples/go.mod | 27 +-- examples/go.sum | 54 ++--- examples/minimal-server/fiber/Makefile | 36 +++ examples/minimal-server/fiber/go.mod | 44 ++++ examples/minimal-server/fiber/go.sum | 198 +++++++++++++++ examples/petstore-expanded/fiber/Makefile | 36 +++ examples/petstore-expanded/fiber/go.mod | 53 ++++ examples/petstore-expanded/fiber/go.sum | 212 ++++++++++++++++ internal/test/Makefile | 31 +-- internal/test/go.mod | 30 +-- internal/test/go.sum | 60 ++--- internal/test/issues/issue1469/Makefile | 36 +++ internal/test/issues/issue1469/go.mod | 49 ++++ internal/test/issues/issue1469/go.sum | 198 +++++++++++++++ internal/test/strict-server/fiber/Makefile | 36 +++ .../strict-server/fiber/fiber_strict_test.go | 229 ++++++++++++++++++ internal/test/strict-server/fiber/go.mod | 55 +++++ internal/test/strict-server/fiber/go.sum | 210 ++++++++++++++++ internal/test/strict-server/stdhttp/Makefile | 18 +- internal/test/strict-server/stdhttp/go.mod | 12 +- internal/test/strict-server/stdhttp/go.sum | 28 +-- internal/test/strict-server/strict_test.go | 11 - 24 files changed, 1529 insertions(+), 193 deletions(-) create mode 100644 examples/minimal-server/fiber/Makefile create mode 100644 examples/minimal-server/fiber/go.mod create mode 100644 examples/minimal-server/fiber/go.sum create mode 100644 examples/petstore-expanded/fiber/Makefile create mode 100644 examples/petstore-expanded/fiber/go.mod create mode 100644 examples/petstore-expanded/fiber/go.sum create mode 100644 internal/test/issues/issue1469/Makefile create mode 100644 internal/test/issues/issue1469/go.mod create mode 100644 internal/test/issues/issue1469/go.sum create mode 100644 internal/test/strict-server/fiber/Makefile create mode 100644 internal/test/strict-server/fiber/fiber_strict_test.go create mode 100644 internal/test/strict-server/fiber/go.mod create mode 100644 internal/test/strict-server/fiber/go.sum diff --git a/README.md b/README.md index a81ccc92d1..40c1853278 100644 --- a/README.md +++ b/README.md @@ -423,6 +423,9 @@ Server generate flag to enable code generation +Required Go Version + + Example usage @@ -437,6 +440,9 @@ Example usage chi-server +1.22+ + + For a Chi server, you will want a configuration file such as: @@ -465,6 +471,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: @@ -491,7 +500,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: @@ -521,6 +532,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: @@ -548,7 +562,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: @@ -576,7 +592,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: @@ -604,7 +622,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: diff --git a/examples/Makefile b/examples/Makefile index bb37d63394..5ec0edd058 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-124,go generate ./...) + go generate ./... test: - $(call execute-if-go-124,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-124,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-124,tidied -verbose) + tidied -verbose diff --git a/examples/go.mod b/examples/go.mod index 011b9ad67a..89ce0af263 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.24.0 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ @@ -8,14 +8,12 @@ require ( github.com/getkin/kin-openapi v0.133.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.11 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/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 @@ -32,12 +30,11 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.2.0 // indirect + github.com/andybalholm/brotli v1.1.0 // 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/clipperhouse/uax29/v2 v2.6.0 // 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 @@ -65,7 +62,7 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -76,9 +73,8 @@ require ( github.com/lestrrat-go/option v1.0.1 // 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.14 // 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.19 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -99,7 +95,6 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.69.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -107,14 +102,14 @@ require ( github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.48.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.30.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 diff --git a/examples/go.sum b/examples/go.sum index 0f5c1ca023..d7a256ee0e 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -13,8 +13,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 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= @@ -27,8 +27,6 @@ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4 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.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= -github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 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= @@ -81,8 +79,6 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= 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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -141,8 +137,8 @@ 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.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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= @@ -177,12 +173,11 @@ github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqA 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.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +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.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -200,8 +195,6 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oapi-codegen/echo-middleware v1.0.2 h1:oNBqiE7jd/9bfGNk/bpbX2nqWrtPc+LL4Boya8Wl81U= github.com/oapi-codegen/echo-middleware v1.0.2/go.mod h1:5J6MFcGqrpWLXpbKGZtRPZViLIHyyyUHlkqg6dT2R4E= -github.com/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI= -github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg= github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFDAUUWaJT0k0eI= github.com/oapi-codegen/gin-middleware v1.0.2/go.mod h1:2HJDQjH8jzK2/k/VKcWl+/T41H7ai2bKa6dN3AA2GpA= github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq1eze4mamhT5hU= @@ -282,8 +275,6 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= -github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= 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/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= @@ -300,8 +291,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -321,8 +310,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -330,8 +319,8 @@ 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -345,16 +334,16 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -373,11 +362,12 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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= @@ -388,8 +378,8 @@ 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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -399,8 +389,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/examples/minimal-server/fiber/Makefile b/examples/minimal-server/fiber/Makefile new file mode 100644 index 0000000000..bb37d63394 --- /dev/null +++ b/examples/minimal-server/fiber/Makefile @@ -0,0 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/examples/minimal-server/fiber/go.mod b/examples/minimal-server/fiber/go.mod new file mode 100644 index 0000000000..58abd2fa35 --- /dev/null +++ b/examples/minimal-server/fiber/go.mod @@ -0,0 +1,44 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber + +go 1.24.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require github.com/gofiber/fiber/v2 v2.52.11 + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // 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.16 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/minimal-server/fiber/go.sum b/examples/minimal-server/fiber/go.sum new file mode 100644 index 0000000000..e2954b1efc --- /dev/null +++ b/examples/minimal-server/fiber/go.sum @@ -0,0 +1,198 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +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/examples/petstore-expanded/fiber/Makefile b/examples/petstore-expanded/fiber/Makefile new file mode 100644 index 0000000000..bb37d63394 --- /dev/null +++ b/examples/petstore-expanded/fiber/Makefile @@ -0,0 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/examples/petstore-expanded/fiber/go.mod b/examples/petstore-expanded/fiber/go.mod new file mode 100644 index 0000000000..a93bf57445 --- /dev/null +++ b/examples/petstore-expanded/fiber/go.mod @@ -0,0 +1,53 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/fiber + +go 1.24.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/getkin/kin-openapi v0.133.0 + github.com/gofiber/fiber/v2 v2.52.11 + github.com/oapi-codegen/fiber-middleware v1.0.2 + github.com/oapi-codegen/runtime v1.1.0 + github.com/stretchr/testify v1.11.1 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // 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.16 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/petstore-expanded/fiber/go.sum b/examples/petstore-expanded/fiber/go.sum new file mode 100644 index 0000000000..62ff2f51fd --- /dev/null +++ b/examples/petstore-expanded/fiber/go.sum @@ -0,0 +1,212 @@ +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/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/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/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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/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/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI= +github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg= +github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM= +github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +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 bb37d63394..5ec0edd058 100644 --- a/internal/test/Makefile +++ b/internal/test/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-124,go generate ./...) + go generate ./... test: - $(call execute-if-go-124,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-124,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-124,tidied -verbose) + tidied -verbose diff --git a/internal/test/go.mod b/internal/test/go.mod index 6d321d86bf..4d9e591610 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.24.0 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ @@ -8,8 +8,7 @@ require ( github.com/getkin/kin-openapi v0.133.0 github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi/v5 v5.0.10 - github.com/gofiber/fiber/v2 v2.52.11 - github.com/google/uuid v1.6.0 + github.com/google/uuid v1.4.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 @@ -27,13 +26,12 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.2.0 // indirect + github.com/andybalholm/brotli v1.0.5 // 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/clipperhouse/uax29/v2 v2.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -58,15 +56,14 @@ require ( github.com/kataras/pio v0.0.12 // indirect github.com/kataras/sitemap v0.0.6 // indirect github.com/kataras/tunnel v0.0.4 // indirect - github.com/klauspost/compress v1.18.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/mailgun/raymond/v2 v2.0.48 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -87,7 +84,6 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.69.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -95,14 +91,14 @@ require ( github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.48.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.30.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index 336b745da8..994b539a63 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -13,8 +13,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -33,8 +33,6 @@ github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI 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.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= -github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 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= @@ -80,8 +78,6 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= 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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -107,8 +103,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD 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/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/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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -140,8 +136,8 @@ 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.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +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= @@ -164,13 +160,12 @@ github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNf 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.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +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.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.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +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/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -261,8 +256,6 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= -github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -280,8 +273,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -298,12 +289,12 @@ golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -313,14 +304,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -340,26 +331,27 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc 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-20211216021012-1d35b9e2eb4e/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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 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/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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/internal/test/issues/issue1469/Makefile b/internal/test/issues/issue1469/Makefile new file mode 100644 index 0000000000..bb37d63394 --- /dev/null +++ b/internal/test/issues/issue1469/Makefile @@ -0,0 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/issues/issue1469/go.mod b/internal/test/issues/issue1469/go.mod new file mode 100644 index 0000000000..fbd28f728a --- /dev/null +++ b/internal/test/issues/issue1469/go.mod @@ -0,0 +1,49 @@ +module github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue1469 + +go 1.24.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/gofiber/fiber/v2 v2.52.11 + github.com/stretchr/testify v1.11.1 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // 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.16 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/internal/test/issues/issue1469/go.sum b/internal/test/issues/issue1469/go.sum new file mode 100644 index 0000000000..e2954b1efc --- /dev/null +++ b/internal/test/issues/issue1469/go.sum @@ -0,0 +1,198 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +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/strict-server/fiber/Makefile b/internal/test/strict-server/fiber/Makefile new file mode 100644 index 0000000000..bb37d63394 --- /dev/null +++ b/internal/test/strict-server/fiber/Makefile @@ -0,0 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) 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..cb8b509b08 --- /dev/null +++ b/internal/test/strict-server/fiber/fiber_strict_test.go @@ -0,0 +1,229 @@ +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("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/go.mod b/internal/test/strict-server/fiber/go.mod new file mode 100644 index 0000000000..add341aacf --- /dev/null +++ b/internal/test/strict-server/fiber/go.mod @@ -0,0 +1,55 @@ +module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/fiber + +go 1.24.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ + +replace github.com/oapi-codegen/oapi-codegen/v2/internal/test => ../.. + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/getkin/kin-openapi v0.133.0 + github.com/gofiber/fiber/v2 v2.52.11 + 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.0.0 + github.com/stretchr/testify v1.11.1 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // 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.16 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/tools v0.30.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/fiber/go.sum b/internal/test/strict-server/fiber/go.sum new file mode 100644 index 0000000000..f585043c1b --- /dev/null +++ b/internal/test/strict-server/fiber/go.sum @@ -0,0 +1,210 @@ +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/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/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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +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/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile index bb37d63394..48fe768e30 100644 --- a/internal/test/strict-server/stdhttp/Makefile +++ b/internal/test/strict-server/stdhttp/Makefile @@ -6,31 +6,31 @@ RESET := \e[0;0m GOVER := $(shell go env GOVERSION) GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") -define execute-if-go-124 +define execute-if-go-122 @{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ +if [[ 22 -le $(GOMINOR) ]]; then \ $1; \ else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ + 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-124,$(GOBIN)/golangci-lint run ./...) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...) lint-ci: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) generate: - $(call execute-if-go-124,go generate ./...) + $(call execute-if-go-122,go generate ./...) test: - $(call execute-if-go-124,go test -cover ./...) + $(call execute-if-go-122,go test -cover ./...) tidy: - $(call execute-if-go-124,go mod tidy) + $(call execute-if-go-122,go mod tidy) tidy-ci: - $(call execute-if-go-124,tidied -verbose) + $(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 index cdd0f48f20..b56e4799a0 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp -go 1.24.0 +go 1.22.5 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ @@ -21,7 +21,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/uuid v1.4.0 // 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 @@ -33,10 +33,10 @@ require ( github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.32.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/tools v0.30.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 index c5c399b374..880c5ff529 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -39,8 +39,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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/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/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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -110,8 +110,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -119,13 +119,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -140,21 +140,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index 0ae094df02..03cade9cc9 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" From db8d6b5a99c8ac7bf063f930cf8eff86c3291ff9 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 12 Feb 2026 10:16:51 -0800 Subject: [PATCH 168/293] Run golangci-lint on a supported Go version We only need to run lint on a single version of Go, as the output isn't Go runtime dependent, however, we need to be careful to run it in an environment where the Go runtime isn't newer than what the golangci-lint executable was built with, because it panics on some kind of version check in that case. Resolves: #2214 --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a7d578881..b21f3f88ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,9 @@ permissions: contents: read jobs: build: - uses: oapi-codegen/actions/.github/workflows/ci.yml@b9f2c274c1c631e648931dbbcc1942c2b2027837 # v0.4.0 + uses: oapi-codegen/actions/.github/workflows/ci.yml@75566d848d25021f137594c947f26171094fb511 # v0.5.0 + with: + lint_versions: '["1.25"]' build-binaries: runs-on: ubuntu-latest From b7ac5dbc080606ca893ae3ff2218c444c9760ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haylee=20Sch=C3=A4fer?= Date: Fri, 13 Feb 2026 20:30:00 +0100 Subject: [PATCH 169/293] feat: add support for custom package alias for external ref imports (#2211) * support specifying package alias * update test * fix local package * simplify --- .../test/externalref/externalref.cfg.yaml | 2 +- internal/test/externalref/externalref.gen.go | 12 ++++---- pkg/codegen/codegen.go | 29 +++++++++++++++---- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/internal/test/externalref/externalref.cfg.yaml b/internal/test/externalref/externalref.cfg.yaml index 22a76c3ffd..dd7a93d019 100644 --- a/internal/test/externalref/externalref.cfg.yaml +++ b/internal/test/externalref/externalref.cfg.yaml @@ -5,7 +5,7 @@ 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 + ./packageB/spec.yaml: package_b 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 output: externalref.gen.go output-options: diff --git a/internal/test/externalref/externalref.gen.go b/internal/test/externalref/externalref.gen.go index a1bd9f6ea2..158a922d02 100644 --- a/internal/test/externalref/externalref.gen.go +++ b/internal/test/externalref/externalref.gen.go @@ -14,16 +14,16 @@ 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 @@ -82,13 +82,13 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { } res[rawPath] = rawFunc } - for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "./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(path.Dir(pathToFile), "https://petstore3.swagger.io/api/v3/openapi.json")) { + for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "https://petstore3.swagger.io/api/v3/openapi.json")) { if _, ok := res[rawPath]; ok { // it is not possible to compare functions in golang, so always overwrite the old value } diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 279ed9d081..ce259c42f4 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -90,8 +90,8 @@ func (im importMap) GoImports() []string { func constructImportMapping(importMapping map[string]string) importMap { var ( - pathToName = map[string]string{} - result = importMap{} + pathToImport = importMap{} + result = importMap{} ) { @@ -102,13 +102,32 @@ func constructImportMapping(importMapping map[string]string) importMap { sort.Strings(packagePaths) for _, packagePath := range packagePaths { - if _, ok := pathToName[packagePath]; !ok && packagePath != importMappingCurrentPackage { - 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 } From 01d4fc0aae7f8802f2d2ece9222d5e59b6f20bf1 Mon Sep 17 00:00:00 2001 From: Brahm Lower Date: Fri, 13 Feb 2026 14:34:20 -0800 Subject: [PATCH 170/293] fix: escape quoted media type directives (#2217) * fix: escape quoted media type directives fixes https://github.com/oapi-codegen/oapi-codegen/issues/1529 * squashme: expanded tests to cover iris, fiber & echo tests * squashme: added makefile to fiber test directory, fixing root level tests * squashme: actually fixed the generate issues with fiber tests * squashme: skip fiber test for go versions <1.24 * squashme: make actually uses the execute-if-go-124 function --- .../issues/issue-1529/strict-echo/config.yaml | 9 + .../test/issues/issue-1529/strict-echo/doc.go | 3 + .../issue-1529/strict-echo/issue1529.gen.go | 471 ++++++++++++++++++ .../issues/issue-1529/strict-echo/spec.yaml | 21 + .../issues/issue-1529/strict-fiber/Makefile | 36 ++ .../issue-1529/strict-fiber/config.yaml | 9 + .../issues/issue-1529/strict-fiber/doc.go | 3 + .../issues/issue-1529/strict-fiber/go.mod | 46 ++ .../issues/issue-1529/strict-fiber/go.sum | 198 ++++++++ .../issue-1529/strict-fiber/issue1529.gen.go | 465 +++++++++++++++++ .../issues/issue-1529/strict-fiber/spec.yaml | 21 + .../issues/issue-1529/strict-iris/config.yaml | 9 + .../test/issues/issue-1529/strict-iris/doc.go | 3 + .../issue-1529/strict-iris/issue1529.gen.go | 466 +++++++++++++++++ .../issues/issue-1529/strict-iris/spec.yaml | 21 + pkg/codegen/template_helpers.go | 7 +- .../strict/strict-fiber-interface.tmpl | 2 +- .../templates/strict/strict-interface.tmpl | 2 +- .../strict/strict-iris-interface.tmpl | 2 +- pkg/codegen/utils.go | 7 + pkg/codegen/utils_test.go | 30 ++ 21 files changed, 1826 insertions(+), 5 deletions(-) create mode 100644 internal/test/issues/issue-1529/strict-echo/config.yaml create mode 100644 internal/test/issues/issue-1529/strict-echo/doc.go create mode 100644 internal/test/issues/issue-1529/strict-echo/issue1529.gen.go create mode 100644 internal/test/issues/issue-1529/strict-echo/spec.yaml create mode 100644 internal/test/issues/issue-1529/strict-fiber/Makefile create mode 100644 internal/test/issues/issue-1529/strict-fiber/config.yaml create mode 100644 internal/test/issues/issue-1529/strict-fiber/doc.go create mode 100644 internal/test/issues/issue-1529/strict-fiber/go.mod create mode 100644 internal/test/issues/issue-1529/strict-fiber/go.sum create mode 100644 internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go create mode 100644 internal/test/issues/issue-1529/strict-fiber/spec.yaml create mode 100644 internal/test/issues/issue-1529/strict-iris/config.yaml create mode 100644 internal/test/issues/issue-1529/strict-iris/doc.go create mode 100644 internal/test/issues/issue-1529/strict-iris/issue1529.gen.go create mode 100644 internal/test/issues/issue-1529/strict-iris/spec.yaml 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..cd5260fae4 --- /dev/null +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -0,0 +1,471 @@ +// 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/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" + strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo" +) + +// 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("GET", 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 +} + +// 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 +} + +// 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 +} + +// 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+"/test", wrapper.Test) + +} + +type TestRequestObject struct { +} + +type TestResponseObject interface { + VisitTestResponse(w http.ResponseWriter) error +} + +type Test200JSONResponse Test + +func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type Test200ApplicationJSONProfileBarResponse Test + +func (response Test200ApplicationJSONProfileBarResponse) VisitTestResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json; profile=\"Bar\"") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type Test200ApplicationJSONProfileFooResponse Test + +func (response Test200ApplicationJSONProfileFooResponse) VisitTestResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json; profile=\"Foo\"") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + + // (GET /test) + Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error) +} + +type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc +type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc + +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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", + "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", + "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", + "n0X+YG7zHQAA//9fnz6pkQEAAA==", +} + +// 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/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/Makefile b/internal/test/issues/issue-1529/strict-fiber/Makefile new file mode 100644 index 0000000000..bb37d63394 --- /dev/null +++ b/internal/test/issues/issue-1529/strict-fiber/Makefile @@ -0,0 +1,36 @@ +SHELL:=/bin/bash + +YELLOW := \e[0;33m +RESET := \e[0;0m + +GOVER := $(shell go env GOVERSION) +GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") + +define execute-if-go-124 +@{ \ +if [[ 24 -le $(GOMINOR) ]]; then \ + $1; \ +else \ + echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ +fi \ +} +endef + +lint: + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) + +lint-ci: + + $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + +generate: + $(call execute-if-go-124,go generate ./...) + +test: + $(call execute-if-go-124,go test -cover ./...) + +tidy: + $(call execute-if-go-124,go mod tidy) + +tidy-ci: + $(call execute-if-go-124,tidied -verbose) 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/go.mod b/internal/test/issues/issue-1529/strict-fiber/go.mod new file mode 100644 index 0000000000..5e881be269 --- /dev/null +++ b/internal/test/issues/issue-1529/strict-fiber/go.mod @@ -0,0 +1,46 @@ +module github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1529/strict-fiber + +go 1.24.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/getkin/kin-openapi v0.133.0 + github.com/gofiber/fiber/v2 v2.52.11 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // 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.16 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/internal/test/issues/issue-1529/strict-fiber/go.sum b/internal/test/issues/issue-1529/strict-fiber/go.sum new file mode 100644 index 0000000000..e2954b1efc --- /dev/null +++ b/internal/test/issues/issue-1529/strict-fiber/go.sum @@ -0,0 +1,198 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +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/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..4d6ab516f5 --- /dev/null +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -0,0 +1,465 @@ +// Package issue1529 provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +package issue1529 + +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/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("GET", 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 +} + +// 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 +} + +// 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 +} + +type MiddlewareFunc fiber.Handler + +// Test operation middleware +func (siw *ServerInterfaceWrapper) Test(c *fiber.Ctx) error { + + return siw.Handler.Test(c) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc +} + +// 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, + } + + 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 interface{}) (interface{}, 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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", + "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", + "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", + "n0X+YG7zHQAA//9fnz6pkQEAAA==", +} + +// 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/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..a214576e80 --- /dev/null +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -0,0 +1,466 @@ +// 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/gzip" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/kataras/iris/v12" + strictiris "github.com/oapi-codegen/runtime/strictmiddleware/iris" +) + +// 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("GET", 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 +} + +// 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 +} + +// 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 = strictiris.StrictIrisHandlerFunc +type StrictMiddlewareFunc = strictiris.StrictIrisMiddlewareFunc + +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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", + "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", + "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", + "n0X+YG7zHQAA//9fnz6pkQEAAA==", +} + +// 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/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/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 49ee3aba64..64caf12828 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -246,14 +246,16 @@ 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 } @@ -343,6 +345,7 @@ var TemplateFunctions = template.FuncMap{ "title": titleCaser.String, "stripNewLines": stripNewLines, "sanitizeGoIdentity": SanitizeGoIdentity, + "toGoString": StringToGoString, "toGoComment": StringWithTypeNameToGoComment, "genServerURLWithVariablesFunctionParams": genServerURLWithVariablesFunctionParams, diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index 8bcfc89b10..e83f7e38aa 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -77,7 +77,7 @@ {{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}}", 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)) diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index e19936d6a7..ac4b56fdbb 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -74,7 +74,7 @@ {{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}}) + 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 | toGoString}}{{else}}response.ContentType{{end}}) {{if not .IsSupported -}} if response.ContentLength != 0 { w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 5ebbc4e1b3..95b78d0645 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -79,7 +79,7 @@ {{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}}", 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)) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 691d887663..89a9c31256 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -864,6 +864,13 @@ 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\""` +func StringToGoString(in string) string { + esc := strings.ReplaceAll(in, "\"", "\\\"") + return fmt.Sprintf("\"%s\"", esc) +} + // StringToGoComment renders a possible multi-line string as a valid Go-Comment. // Each line is prefixed as a comment. func StringToGoComment(in string) string { diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 0666fc9909..aaea643721 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -469,6 +469,36 @@ 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", + }, + } + 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 From 1650807a81afff00eb4447f8ef332e41fcc01c18 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sun, 15 Feb 2026 07:01:44 -0800 Subject: [PATCH 171/293] fix: handle duplicate path parameters in OpenAPI specs (#2220) Some real-world OpenAPI specs (e.g. Keycloak) reuse the same path parameter more than once in a single URI, such as: /clients/{client-uuid}/roles/{role-name}/composites/clients/{client-uuid} Previously this caused a "has 4 positional parameters, but spec has 3 declared" error because SortParamsByPath compared raw URI placeholder count against unique declared parameters. Fix this by deduplicating the path parameters extracted from the URI (preserving first-occurrence order) before matching them against the spec declared parameters. This is the right level to fix the issue rather than scattering dedup logic across template helpers. Fixes #1574 Supersedes #2175 Co-authored-by: Junior Rantila Co-authored-by: Claude Opus 4.6 --- pkg/codegen/codegen_test.go | 60 +++++++++++++++++++++++++++++++++++++ pkg/codegen/utils.go | 22 +++++++++++--- pkg/codegen/utils_test.go | 47 +++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 4 deletions(-) diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 7b22faed01..ff3c86d9ba 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -227,5 +227,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/utils.go b/pkg/codegen/utils.go index 89a9c31256..79e274f7ee 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -654,15 +654,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", diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index aaea643721..f204fc50c8 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -462,6 +462,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) { From fca3f0fedd22c8e372ecc0811aefaea33f33a845 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sun, 15 Feb 2026 07:02:07 -0800 Subject: [PATCH 172/293] Fix schema gathering oversight (#2219) Response and RequestBodies need to include any additional types into model generation. This is an ancient bug, from the very first days of oapi-codegen. Extend the issue-200 spec with inline objects containing additionalProperties inside components/responses and components/requestBodies. The test confirms the codegen produces named types (Bar_Pagination, Bar_Metadata) for these inline schemas. Co-authored-by: Claude Opus 4.6 --- .../test/issues/issue-200/issue200.gen.go | 258 +++++++++++++++++- .../test/issues/issue-200/issue200_test.go | 15 + internal/test/issues/issue-200/spec.yaml | 16 ++ pkg/codegen/codegen.go | 2 + 4 files changed, 285 insertions(+), 6 deletions(-) diff --git a/internal/test/issues/issue-200/issue200.gen.go b/internal/test/issues/issue-200/issue200.gen.go index cc3c138314..530c042c7a 100644 --- a/internal/test/issues/issue-200/issue200.gen.go +++ b/internal/test/issues/issue-200/issue200.gen.go @@ -3,6 +3,11 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package issue200 +import ( + "encoding/json" + "fmt" +) + // Bar defines model for Bar. type Bar struct { Value *string `json:"value,omitempty"` @@ -24,20 +29,36 @@ type BarParameter = string // BarResponse defines model for Bar. type BarResponse struct { - Value1 *Bar `json:"value1,omitempty"` - Value2 *Bar2 `json:"value2,omitempty"` - Value3 *BarParam `json:"value3,omitempty"` - Value4 *BarParam2 `json:"value4,omitempty"` + Pagination *Bar_Pagination `json:"pagination,omitempty"` + Value1 *Bar `json:"value1,omitempty"` + Value2 *Bar2 `json:"value2,omitempty"` + Value3 *BarParam `json:"value3,omitempty"` + Value4 *BarParam2 `json:"value4,omitempty"` +} + +// Bar_Pagination defines model for Bar.Pagination. +type Bar_Pagination struct { + Page *int `json:"page,omitempty"` + TotalPages *int `json:"totalPages,omitempty"` + AdditionalProperties map[string]string `json:"-"` } // BarRequestBody defines model for Bar. type BarRequestBody struct { - Value *int `json:"value,omitempty"` + Metadata *Bar_Metadata `json:"metadata,omitempty"` + Value *int `json:"value,omitempty"` +} + +// Bar_Metadata defines model for Bar.Metadata. +type Bar_Metadata struct { + Key *string `json:"key,omitempty"` + AdditionalProperties map[string]string `json:"-"` } // PostFooJSONBody defines parameters for PostFoo. type PostFooJSONBody struct { - Value *int `json:"value,omitempty"` + Metadata *PostFooJSONBody_Metadata `json:"metadata,omitempty"` + Value *int `json:"value,omitempty"` } // PostFooParams defines parameters for PostFoo. @@ -45,5 +66,230 @@ type PostFooParams struct { Bar *Bar `form:"Bar,omitempty" json:"Bar,omitempty"` } +// PostFooJSONBody_Metadata defines parameters for PostFoo. +type PostFooJSONBody_Metadata struct { + Key *string `json:"key,omitempty"` + AdditionalProperties map[string]string `json:"-"` +} + // PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. type PostFooJSONRequestBody PostFooJSONBody + +// Getter for additional properties for PostFooJSONBody_Metadata. Returns the specified +// element and whether it was found +func (a PostFooJSONBody_Metadata) Get(fieldName string) (value string, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for PostFooJSONBody_Metadata +func (a *PostFooJSONBody_Metadata) Set(fieldName string, value string) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]string) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for PostFooJSONBody_Metadata to handle AdditionalProperties +func (a *PostFooJSONBody_Metadata) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["key"]; found { + err = json.Unmarshal(raw, &a.Key) + if err != nil { + return fmt.Errorf("error reading 'key': %w", err) + } + delete(object, "key") + } + + 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 PostFooJSONBody_Metadata to handle AdditionalProperties +func (a PostFooJSONBody_Metadata) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + if a.Key != nil { + object["key"], err = json.Marshal(a.Key) + if err != nil { + return nil, fmt.Errorf("error marshaling 'key': %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 Bar_Pagination. Returns the specified +// element and whether it was found +func (a Bar_Pagination) Get(fieldName string) (value string, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for Bar_Pagination +func (a *Bar_Pagination) Set(fieldName string, value string) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]string) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for Bar_Pagination to handle AdditionalProperties +func (a *Bar_Pagination) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["page"]; found { + err = json.Unmarshal(raw, &a.Page) + if err != nil { + return fmt.Errorf("error reading 'page': %w", err) + } + delete(object, "page") + } + + if raw, found := object["totalPages"]; found { + err = json.Unmarshal(raw, &a.TotalPages) + if err != nil { + return fmt.Errorf("error reading 'totalPages': %w", err) + } + delete(object, "totalPages") + } + + 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 Bar_Pagination to handle AdditionalProperties +func (a Bar_Pagination) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + if a.Page != nil { + object["page"], err = json.Marshal(a.Page) + if err != nil { + return nil, fmt.Errorf("error marshaling 'page': %w", err) + } + } + + if a.TotalPages != nil { + object["totalPages"], err = json.Marshal(a.TotalPages) + if err != nil { + return nil, fmt.Errorf("error marshaling 'totalPages': %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 Bar_Metadata. Returns the specified +// element and whether it was found +func (a Bar_Metadata) Get(fieldName string) (value string, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for Bar_Metadata +func (a *Bar_Metadata) Set(fieldName string, value string) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]string) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for Bar_Metadata to handle AdditionalProperties +func (a *Bar_Metadata) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["key"]; found { + err = json.Unmarshal(raw, &a.Key) + if err != nil { + return fmt.Errorf("error reading 'key': %w", err) + } + delete(object, "key") + } + + 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 Bar_Metadata to handle AdditionalProperties +func (a Bar_Metadata) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + if a.Key != nil { + object["key"], err = json.Marshal(a.Key) + if err != nil { + return nil, fmt.Errorf("error marshaling 'key': %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-200/issue200_test.go b/internal/test/issues/issue-200/issue200_test.go index 9f690d520c..96fdb62e8b 100644 --- a/internal/test/issues/issue-200/issue200_test.go +++ b/internal/test/issues/issue-200/issue200_test.go @@ -35,6 +35,21 @@ func TestDuplicateTypeNamesCompile(t *testing.T) { // RequestBody type: BarRequestBody (was "Bar" in components/requestBodies) _ = BarRequestBody{Value: ptr(42)} + // Inline nested object with additionalProperties inside a response + // must produce a named AdditionalType (not get silently dropped). + _ = Bar_Pagination{ + Page: ptr(1), + TotalPages: ptr(10), + AdditionalProperties: map[string]string{"cursor": "abc"}, + } + + // Inline nested object with additionalProperties inside a requestBody + // must produce a named AdditionalType (not get silently dropped). + _ = Bar_Metadata{ + Key: ptr("k"), + AdditionalProperties: map[string]string{"extra": "val"}, + } + // Operation-derived types _ = PostFooParams{Bar: &Bar{}} _ = PostFooJSONBody{Value: ptr(99)} diff --git a/internal/test/issues/issue-200/spec.yaml b/internal/test/issues/issue-200/spec.yaml index a18c7f403c..2a68f71694 100644 --- a/internal/test/issues/issue-200/spec.yaml +++ b/internal/test/issues/issue-200/spec.yaml @@ -58,6 +58,13 @@ components: properties: value: type: integer + metadata: + type: object + properties: + key: + type: string + additionalProperties: + type: string responses: Bar: @@ -78,3 +85,12 @@ components: $ref: '#/components/schemas/BarParam' value4: $ref: '#/components/schemas/BarParam2' + pagination: + type: object + properties: + page: + type: integer + totalPages: + type: integer + additionalProperties: + type: string diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index ce259c42f4..355de4f7a7 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -714,6 +714,7 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response } types = append(types, typeDef) + types = append(types, goType.AdditionalTypes...) } } return types, nil @@ -762,6 +763,7 @@ 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 From b658fcffa2b8baa059df5a81ff6cf75eeb1d6e9a Mon Sep 17 00:00:00 2001 From: Toby Brain Date: Tue, 17 Feb 2026 03:39:56 +1100 Subject: [PATCH 173/293] Support unions with multiple mappings pointing to a single underlying type (#2071) --- internal/test/issues/issue-1530/config.yaml | 4 + internal/test/issues/issue-1530/doc.go | 3 + .../test/issues/issue-1530/issue1530.gen.go | 126 ++++++++++++++++++ .../test/issues/issue-1530/issue1530.yaml | 57 ++++++++ .../test/issues/issue-1530/issue1530_test.go | 51 +++++++ pkg/codegen/schema.go | 3 +- pkg/codegen/templates/union.tmpl | 37 ++--- 7 files changed, 263 insertions(+), 18 deletions(-) create mode 100644 internal/test/issues/issue-1530/config.yaml create mode 100644 internal/test/issues/issue-1530/doc.go create mode 100644 internal/test/issues/issue-1530/issue1530.gen.go create mode 100644 internal/test/issues/issue-1530/issue1530.yaml create mode 100644 internal/test/issues/issue-1530/issue1530_test.go 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/pkg/codegen/schema.go b/pkg/codegen/schema.go index 7435fa224d..f361ab3465 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -938,7 +938,6 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato if v == element.Ref { outSchema.Discriminator.Mapping[k] = elementSchema.GoType mapped = true - break } } // Implicit mapping. @@ -949,7 +948,7 @@ 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") } diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl index b27a2aca3f..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 -}} From 091742e84c1ac2b9ad41c5be25a0983cf6330976 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 16 Feb 2026 13:08:29 -0800 Subject: [PATCH 174/293] fix(strict-server): generate correct type for `$ref` text responses (#2225) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: add regression test for issue #2190 Add a minimal reproduction for invalid generated code when reusing response components. The generated VisitGetTestResponse method attempts []byte(response) on a struct type, which does not compile. Co-Authored-By: Claude Opus 4.6 * fix: generate correct type for $ref text responses in strict server (#2190) When a response is defined as a $ref to a component response with text/plain content type (and no headers), the strict-server template generated a struct-embedding type whose Visit method tried to call []byte(response) on a struct, which failed to compile. The root cause was the revert of PR #1132 (commit 891a067), which had originally fixed this by making all text responses string types. That PR was reverted because it broke text responses with headers (#1676), which require the struct form with a Body field. The fix extends the existing multipart special case in Branch 1A of the strict-interface template to also cover text responses without headers. This generates a named type alias (e.g. `type GetTest401TextResponse UnauthorizedTextResponse`) instead of a struct embedding, so []byte(response) compiles and works correctly. Text responses with headers continue to go through Branch 1C (struct with Body + Headers fields), so #1676 is unaffected — confirmed by verifying no diff in internal/test/issues/issue-1676/ping.gen.go. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- internal/test/issues/issue-2190/config.yaml | 9 + internal/test/issues/issue-2190/generate.go | 3 + .../test/issues/issue-2190/issue2190.gen.go | 486 ++++++++++++++++++ .../test/issues/issue-2190/issue2190_test.go | 37 ++ internal/test/issues/issue-2190/spec.yaml | 30 ++ .../templates/strict/strict-interface.tmpl | 2 +- 6 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 internal/test/issues/issue-2190/config.yaml create mode 100644 internal/test/issues/issue-2190/generate.go create mode 100644 internal/test/issues/issue-2190/issue2190.gen.go create mode 100644 internal/test/issues/issue-2190/issue2190_test.go create mode 100644 internal/test/issues/issue-2190/spec.yaml 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..c22e32724c --- /dev/null +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -0,0 +1,486 @@ +//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 ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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("GET", 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 +} + +// 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 +} + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +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("GET "+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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index ac4b56fdbb..62f3d4d9c6 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -40,7 +40,7 @@ {{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}} } From 99615d042afbb684c08cca144cd52e4e8e04c9d9 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 16 Feb 2026 13:09:24 -0800 Subject: [PATCH 175/293] fix: handle optional request bodies in strict server mode (#2222) Fixes #2116 Strict server handlers unconditionally decoded the request body, causing an EOF error when no body was sent for operations with optional request bodies (requestBody.required defaults to false in OpenAPI 3.0). For optional JSON bodies, the generated handlers now treat io.EOF from the decoder as "no body provided" and leave request.Body as nil rather than returning an error. For optional text bodies, an empty read is similarly treated as absent. Required bodies retain the original unconditional error handling. All five strict server templates are updated: stdhttp (used by chi and gorilla), echo, gin, fiber, and iris. Two new test operations (RequiredJSONBody, RequiredTextBody) with required: true are added to the strict server test schema to verify both code paths are generated correctly. Co-authored-by: Claude Opus 4.6 --- .../test/issues/issue-1298/issue1298.gen.go | 12 +- internal/test/strict-server/chi/server.gen.go | 281 +++++++++++++++--- internal/test/strict-server/chi/server.go | 8 + internal/test/strict-server/chi/types.gen.go | 9 + .../test/strict-server/client/client.gen.go | 272 +++++++++++++++++ .../test/strict-server/echo/server.gen.go | 243 +++++++++++++-- internal/test/strict-server/echo/server.go | 8 + internal/test/strict-server/echo/types.gen.go | 9 + .../test/strict-server/fiber/server.gen.go | 240 +++++++++++++-- internal/test/strict-server/fiber/server.go | 8 + .../test/strict-server/fiber/types.gen.go | 9 + internal/test/strict-server/gin/server.gen.go | 278 ++++++++++++++--- internal/test/strict-server/gin/server.go | 8 + internal/test/strict-server/gin/types.gen.go | 9 + .../test/strict-server/gorilla/server.gen.go | 269 ++++++++++++++--- internal/test/strict-server/gorilla/server.go | 8 + .../test/strict-server/gorilla/types.gen.go | 9 + .../test/strict-server/iris/server.gen.go | 259 +++++++++++++--- internal/test/strict-server/iris/server.go | 8 + internal/test/strict-server/iris/types.gen.go | 9 + .../test/strict-server/stdhttp/server.gen.go | 267 ++++++++++++++--- internal/test/strict-server/stdhttp/server.go | 8 + .../test/strict-server/stdhttp/types.gen.go | 9 + .../test/strict-server/strict-schema.yaml | 42 +++ pkg/codegen/templates/strict/strict-echo.tmpl | 15 +- .../templates/strict/strict-fiber.tmpl | 15 +- pkg/codegen/templates/strict/strict-gin.tmpl | 17 +- pkg/codegen/templates/strict/strict-http.tmpl | 16 +- pkg/codegen/templates/strict/strict-iris.tmpl | 16 +- 29 files changed, 2098 insertions(+), 263 deletions(-) diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index 94734a5772..2e5a48dc57 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" @@ -372,11 +373,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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)) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index c8c7a09245..443fb094bf 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -39,6 +40,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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 +95,16 @@ func (_ Unimplemented) MultipleRequestAndResponseTypes(w http.ResponseWriter, r 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,6 +210,34 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon 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) { @@ -490,6 +535,12 @@ 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+"/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) }) @@ -716,6 +767,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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"` } @@ -1063,6 +1181,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -1123,10 +1247,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 +1348,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 +1385,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 +1411,69 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, } } +// 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 +1506,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 +1543,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 +1665,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 +1699,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)) @@ -1524,24 +1730,25 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index c135a2a445..914f967268 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -126,6 +126,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/chi/types.gen.go +++ b/internal/test/strict-server/chi/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 5bf1dffb3f..fcdef6c6d9 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 @@ -57,6 +60,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 @@ -165,6 +174,16 @@ type ClientInterface interface { MultipleRequestAndResponseTypesWithTextBody(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, 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 +315,54 @@ func (c *Client) MultipleRequestAndResponseTypesWithTextBody(ctx context.Context 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 { @@ -608,6 +675,82 @@ func NewMultipleRequestAndResponseTypesRequestWithBody(server string, contentTyp 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("POST", 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 + bodyReader = strings.NewReader(string(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("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + // NewReservedGoKeywordParametersRequest generates requests for ReservedGoKeywordParameters func NewReservedGoKeywordParametersRequest(server string, pType string) (*http.Request, error) { var err error @@ -983,6 +1126,16 @@ type ClientWithResponsesInterface interface { MultipleRequestAndResponseTypesWithTextBodyWithResponse(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, 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) @@ -1104,6 +1257,49 @@ func (r MultipleRequestAndResponseTypesResponse) StatusCode() int { return 0 } +type RequiredJSONBodyResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Example +} + +// 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 +} + +type RequiredTextBodyResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + type ReservedGoKeywordParametersResponse struct { Body []byte HTTPResponse *http.Response @@ -1347,6 +1543,40 @@ func (c *ClientWithResponses) MultipleRequestAndResponseTypesWithTextBodyWithRes return ParseMultipleRequestAndResponseTypesResponse(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...) @@ -1546,6 +1776,48 @@ func ParseMultipleRequestAndResponseTypesResponse(rsp *http.Response) (*Multiple 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) diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index f07dfa5e46..78eccb1770 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -39,6 +40,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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,6 +112,24 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Contex 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 @@ -253,6 +278,8 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/multipart", wrapper.MultipartExample) router.POST(baseURL+"/multipart-related", wrapper.MultipartRelatedExample) router.POST(baseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + router.POST(baseURL+"/required-json-body", wrapper.RequiredJSONBody) + router.POST(baseURL+"/required-text-body", wrapper.RequiredTextBody) router.GET(baseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters) router.POST(baseURL+"/reusable-responses", wrapper.ReusableResponses) router.POST(baseURL+"/text", wrapper.TextExample) @@ -462,6 +489,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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"` } @@ -809,6 +903,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -852,9 +952,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 +1045,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 +1078,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 +1103,65 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error 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 +1193,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 +1227,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 +1344,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 +1376,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)) @@ -1227,24 +1405,25 @@ func (sh *strictHandler) UnionExample(ctx echo.Context) error { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index c135a2a445..914f967268 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -126,6 +126,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/echo/types.gen.go +++ b/internal/test/strict-server/echo/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index edf81be1fb..f33ca45430 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -38,6 +39,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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 @@ -94,6 +101,18 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) return siw.Handler.MultipleRequestAndResponseTypes(c) } +// RequiredJSONBody operation middleware +func (siw *ServerInterfaceWrapper) RequiredJSONBody(c *fiber.Ctx) error { + + return siw.Handler.RequiredJSONBody(c) +} + +// RequiredTextBody operation middleware +func (siw *ServerInterfaceWrapper) RequiredTextBody(c *fiber.Ctx) error { + + return siw.Handler.RequiredTextBody(c) +} + // ReservedGoKeywordParameters operation middleware func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) error { @@ -225,6 +244,10 @@ func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, option router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + 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) @@ -441,6 +464,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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"` } @@ -788,6 +878,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -832,9 +928,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)) @@ -925,9 +1024,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 @@ -944,8 +1046,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) { @@ -969,6 +1073,66 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error { 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 @@ -1002,9 +1166,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)) @@ -1032,8 +1199,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)) @@ -1151,9 +1320,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)) @@ -1182,9 +1354,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)) @@ -1210,24 +1385,25 @@ func (sh *strictHandler) UnionExample(ctx *fiber.Ctx) error { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go index c135a2a445..914f967268 100644 --- a/internal/test/strict-server/fiber/server.go +++ b/internal/test/strict-server/fiber/server.go @@ -126,6 +126,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/fiber/types.gen.go +++ b/internal/test/strict-server/fiber/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 21f9f32763..5a5b9c7582 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -39,6 +40,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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,6 +132,32 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex siw.Handler.MultipleRequestAndResponseTypes(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) { @@ -319,6 +352,8 @@ 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+"/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) @@ -527,6 +562,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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"` } @@ -874,6 +976,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -917,11 +1025,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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)) @@ -1019,11 +1130,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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 { @@ -1054,8 +1168,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { ctx.Error(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) { @@ -1079,6 +1195,72 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { } } +// RequiredJSONBody operation middleware +func (sh *strictHandler) RequiredJSONBody(ctx *gin.Context) { + var request RequiredJSONBodyRequestObject + + var body RequiredJSONBodyJSONRequestBody + if err := ctx.ShouldBindJSON(&body); err != nil { + ctx.Status(http.StatusBadRequest) + ctx.Error(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 { + ctx.Error(err) + ctx.Status(http.StatusInternalServerError) + } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok { + if err := validResponse.VisitRequiredJSONBodyResponse(ctx.Writer); err != nil { + ctx.Error(err) + } + } else if response != nil { + ctx.Error(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 { + ctx.Error(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 { + ctx.Error(err) + ctx.Status(http.StatusInternalServerError) + } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok { + if err := validResponse.VisitRequiredTextBodyResponse(ctx.Writer); err != nil { + ctx.Error(err) + } + } else if response != nil { + ctx.Error(fmt.Errorf("unexpected response type: %T", response)) + } +} + // ReservedGoKeywordParameters operation middleware func (sh *strictHandler) ReservedGoKeywordParameters(ctx *gin.Context, pType string) { var request ReservedGoKeywordParametersRequestObject @@ -1112,11 +1294,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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)) @@ -1148,8 +1333,10 @@ func (sh *strictHandler) TextExample(ctx *gin.Context) { ctx.Error(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)) @@ -1272,11 +1459,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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)) @@ -1305,11 +1495,14 @@ 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) { + ctx.Status(http.StatusBadRequest) + ctx.Error(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)) @@ -1335,24 +1528,25 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index c135a2a445..914f967268 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -126,6 +126,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/gin/types.gen.go +++ b/internal/test/strict-server/gin/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index c6b29393df..0650806552 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -39,6 +40,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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,6 +136,34 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon 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) { @@ -422,6 +457,10 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods("POST") + r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods("POST") + + r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods("POST") + r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods("GET") r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods("POST") @@ -639,6 +678,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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"` } @@ -986,6 +1092,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -1046,10 +1158,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 +1259,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 +1296,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 +1322,69 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, } } +// 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 +1417,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 +1454,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 +1576,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 +1610,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)) @@ -1447,24 +1641,25 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gorilla/server.go b/internal/test/strict-server/gorilla/server.go index 5c5d7c9e77..2cb801e035 100644 --- a/internal/test/strict-server/gorilla/server.go +++ b/internal/test/strict-server/gorilla/server.go @@ -102,6 +102,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/gorilla/types.gen.go +++ b/internal/test/strict-server/gorilla/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 7f224b3b37..b592b21a9f 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -39,6 +40,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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,6 +106,20 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx iris.Contex w.Handler.MultipleRequestAndResponseTypes(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) { @@ -238,6 +259,8 @@ 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+"/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 +471,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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"` } @@ -795,6 +885,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -838,10 +934,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 +1044,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 +1081,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 +1110,75 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx iris.Context) { } } +// 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 +1214,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 +1254,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 +1388,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 +1425,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)) @@ -1275,24 +1459,25 @@ func (sh *strictHandler) UnionExample(ctx iris.Context) { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/iris/server.go b/internal/test/strict-server/iris/server.go index c0ab4c7700..f87df99759 100644 --- a/internal/test/strict-server/iris/server.go +++ b/internal/test/strict-server/iris/server.go @@ -125,6 +125,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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..fac014c4bb 100644 --- a/internal/test/strict-server/iris/types.gen.go +++ b/internal/test/strict-server/iris/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 28c36a7ac7..cff46fe6d7 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -11,6 +11,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "mime" @@ -40,6 +41,12 @@ type ServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(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,6 +137,34 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon 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) { @@ -426,6 +461,8 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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("POST "+options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody) + m.HandleFunc("POST "+options.BaseURL+"/required-text-body", wrapper.RequiredTextBody) 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) @@ -636,6 +673,73 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +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"` } @@ -983,6 +1087,12 @@ type StrictServerInterface interface { // (POST /multiple) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, 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) @@ -1043,10 +1153,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)) @@ -1141,10 +1254,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 { @@ -1175,8 +1291,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) { @@ -1199,6 +1317,69 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, } } +// 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 @@ -1231,10 +1412,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)) @@ -1265,8 +1449,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)) @@ -1385,10 +1571,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)) @@ -1416,10 +1605,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,24 +1636,25 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object 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", + "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", + "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", + "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", + "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", + "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", + "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", + "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", + "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", + "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", + "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", + "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", + "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", + "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", + "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", + "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", + "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", + "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", + "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", + "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/stdhttp/server.go b/internal/test/strict-server/stdhttp/server.go index a142a6b813..4f39f939cc 100644 --- a/internal/test/strict-server/stdhttp/server.go +++ b/internal/test/strict-server/stdhttp/server.go @@ -128,6 +128,14 @@ func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableRes 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/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go index 6682c1acab..fac014c4bb 100644 --- a/internal/test/strict-server/stdhttp/types.gen.go +++ b/internal/test/strict-server/stdhttp/types.gen.go @@ -14,6 +14,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 @@ -44,6 +47,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 diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index a0b6a6e054..8b18edd541 100644 --- a/internal/test/strict-server/strict-schema.yaml +++ b/internal/test/strict-server/strict-schema.yaml @@ -247,6 +247,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 diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl index 676690fab3..7b470c8ce7 100644 --- a/pkg/codegen/templates/strict/strict-echo.tmpl +++ b/pkg/codegen/templates/strict/strict-echo.tmpl @@ -34,9 +34,16 @@ type strictHandler struct { {{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 +75,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" */ -}} diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl index 510899c9e0..59a2c0736b 100644 --- a/pkg/codegen/templates/strict/strict-fiber.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber.tmpl @@ -36,9 +36,16 @@ type strictHandler struct { {{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" */ -}} diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index d4c43164a6..40a7b7bcb1 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -34,11 +34,20 @@ type strictHandler struct { {{if .IsJSON }} var body {{$opid}}{{.NameTag}}RequestBody if err := ctx.ShouldBindJSON(&body); err != nil { + {{if not .Required -}} + if !errors.Is(err, io.EOF) { + ctx.Status(http.StatusBadRequest) + ctx.Error(err) + return + } + {{else -}} ctx.Status(http.StatusBadRequest) ctx.Error(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) @@ -75,8 +84,14 @@ type strictHandler struct { ctx.Error(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" */ -}} diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl index 8d32415ad6..7314c26fd7 100644 --- a/pkg/codegen/templates/strict/strict-http.tmpl +++ b/pkg/codegen/templates/strict/strict-http.tmpl @@ -51,10 +51,18 @@ type strictHandler struct { {{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 +99,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" */ -}} diff --git a/pkg/codegen/templates/strict/strict-iris.tmpl b/pkg/codegen/templates/strict/strict-iris.tmpl index dfdeb1546f..6ed301574c 100644 --- a/pkg/codegen/templates/strict/strict-iris.tmpl +++ b/pkg/codegen/templates/strict/strict-iris.tmpl @@ -34,10 +34,18 @@ type strictHandler struct { {{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 +82,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" */ -}} From c6bc7c587515948af319ed804c216aa9fc940f5c Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 16 Feb 2026 13:10:12 -0800 Subject: [PATCH 176/293] feat: add configurable type mapping for OpenAPI primitive types (#2223) * feat: add configurable type mapping for OpenAPI primitive types Supersedes #428, since the original author's branch is gone and his PR only exists in the ref log. Added a TypeMapping configuration that lets users override the default OpenAPI type/format to Go type mappings. User-specified mappings are merged on top of built-in defaults, so only overrides need to be specified. For example, mapping string/date-time to a civil.DateTime or changing the default integer type to int64. Changes: - New TypeMapping, FormatMapping, SimpleTypeSpec types with Merge() and Resolve() methods (pkg/codegen/typemapping.go) - TypeMapping field added to Configuration struct - Merged type mapping stored on globalState, initialized in Generate() - Replaced hardcoded switch statements in oapiSchemaToGoType() with map-based lookups via globalState.typeMapping - Updated configuration-schema.json with type-mapping property and reusable $defs for format-mapping and simple-type-spec - Unit tests for merge, resolve, and default mapping completeness Co-Authored-By: natsukagami Co-Authored-By: Claude Opus 4.6 * Move TypeMapping to OutputOptions * Add example for type-mapping * Address PR feedback Move type-mapping examples to output-options --------- Co-authored-by: natsukagami Co-authored-by: Claude Opus 4.6 --- configuration-schema.json | 59 +++++++++- .../output-options/type-mapping/config.yaml | 14 +++ .../output-options/type-mapping/customdate.go | 3 + .../output-options/type-mapping/generate.go | 6 + .../output-options/type-mapping/spec.yaml | 18 +++ .../type-mapping/typemapping.gen.go | 10 ++ pkg/codegen/codegen.go | 7 ++ pkg/codegen/configuration.go | 4 + pkg/codegen/schema.go | 60 ++-------- pkg/codegen/typemapping.go | 109 ++++++++++++++++++ pkg/codegen/typemapping_test.go | 88 ++++++++++++++ 11 files changed, 329 insertions(+), 49 deletions(-) create mode 100644 examples/output-options/type-mapping/config.yaml create mode 100644 examples/output-options/type-mapping/customdate.go create mode 100644 examples/output-options/type-mapping/generate.go create mode 100644 examples/output-options/type-mapping/spec.yaml create mode 100644 examples/output-options/type-mapping/typemapping.gen.go create mode 100644 pkg/codegen/typemapping.go create mode 100644 pkg/codegen/typemapping_test.go diff --git a/configuration-schema.json b/configuration-schema.json index 8ff58d94b6..43694f9658 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -257,6 +257,25 @@ "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 (e.g., 'Parameter', 'Response', 'RequestBody'). 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" + } + } } } }, @@ -294,5 +313,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/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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 355de4f7a7..0f38b6ff7f 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -52,6 +52,8 @@ var globalState struct { // 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 } // goImport represents a go package to be imported in the generated code @@ -140,6 +142,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) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index d3281fefec..4598bb04ad 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -308,6 +308,10 @@ type OutputOptions struct { // "RequestBody"). 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 { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index f361ab3465..f7b6fd6ac1 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -629,62 +629,26 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem setSkipOptionalPointerForContainerType(outSchema) } else if t.Is("integer") { - // We default to int if format doesn't ask for something else. - switch f { - case "int64", - "int32", - "int16", - "int8", - "int", - "uint64", - "uint32", - "uint16", - "uint8", - "uint": - outSchema.GoType = f - default: - 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" - switch f { - case "double": - outSchema.GoType = "float64" - case "float", "": - outSchema.GoType = "float32" - default: - 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" + spec := globalState.typeMapping.String.Resolve(f) + outSchema.GoType = spec.Type + // Preserve special behaviors for specific types + if outSchema.GoType == "[]byte" { setSkipOptionalPointerForContainerType(outSchema) - 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" + } + 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 { diff --git a/pkg/codegen/typemapping.go b/pkg/codegen/typemapping.go new file mode 100644 index 0000000000..f5e20b54ac --- /dev/null +++ b/pkg/codegen/typemapping.go @@ -0,0 +1,109 @@ +package codegen + +// 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,omitempty"` + Number FormatMapping `yaml:"number,omitempty" json:"number,omitempty"` + Boolean FormatMapping `yaml:"boolean,omitempty" json:"boolean,omitempty"` + String FormatMapping `yaml:"string,omitempty" json:"string,omitempty"` +} + +// 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 + for k, v := range base.Formats { + result.Formats[k] = v + } + + // Override with user default if specified + if user.Default.Type != "" { + result.Default = user.Default + } + + // Override/add user formats + for k, v := range user.Formats { + result.Formats[k] = v + } + + 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) +} From 77bda899b50b9d628b84e4af1356455146c54850 Mon Sep 17 00:00:00 2001 From: Markus Meyer Date: Mon, 16 Feb 2026 22:15:04 +0100 Subject: [PATCH 177/293] fix(overlay): set indentation to 2 when marshalling spec for overlay (#2172) As noted in #2171, this is a workaround for yaml/go-yaml#76. --- pkg/util/loader.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/util/loader.go b/pkg/util/loader.go index 89830a8c44..7eea07b156 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -48,13 +48,17 @@ func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (s } // parse out the yaml.Node, which is required by the overlay library - data, err := yaml.Marshal(spec) + 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(bytes.NewReader(data)).Decode(&node) + err = yaml.NewDecoder(buf).Decode(&node) if err != nil { return nil, fmt.Errorf("failed to parse spec from %#v: %w", filePath, err) } From 59fb0e86773ac572016038c9cd21569de8d6a1b2 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 16 Feb 2026 21:34:02 +0000 Subject: [PATCH 178/293] fix(server-urls): use URL in GoDoc if `description` is empty Otherwise the sentence ends abruptly. --- examples/generate/serverurls/gen.go | 9 +-------- pkg/codegen/templates/server-urls.tmpl | 3 +-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/examples/generate/serverurls/gen.go b/examples/generate/serverurls/gen.go index 5f9e069d3e..b32073b2cd 100644 --- a/examples/generate/serverurls/gen.go +++ b/examples/generate/serverurls/gen.go @@ -9,25 +9,18 @@ import ( ) // 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:80" -// ServerUrlHttplocalhost443 defines the Server URL for -const ServerUrlHttplocalhost443 = "http://localhost:443" +// ServerUrlHttplocalhost443 defines the Server URL for 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:80" // 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 diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl index f3599e5fa6..1c60e796b1 100644 --- a/pkg/codegen/templates/server-urls.tmpl +++ b/pkg/codegen/templates/server-urls.tmpl @@ -1,8 +1,7 @@ {{ range . }} {{ if eq 0 (len .OAPISchema.Variables) }} {{/* URLs without variables are straightforward, so we'll create them a constant */}} -// {{ .GoName }} defines the Server URL for {{ .OAPISchema.Description }} -const {{ .GoName}} = "{{ .OAPISchema.URL }}" +// {{ .GoName }} defines the Server URL for {{ if len .OAPISchema.Description }}{{ .OAPISchema.Description }}{{ else }}{{ .OAPISchema.URL }}{{ end }} {{ else }} {{/* URLs with variables are not straightforward, as we may need multiple types, and so will model them as a function */}} From f4ac5dface79675318a6dc598968cd6ae85862ff Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Tue, 17 Feb 2026 06:24:08 +0300 Subject: [PATCH 179/293] Support nullable slice elements and map values (#2185) --- pkg/codegen/codegen_test.go | 9 ++++++++- pkg/codegen/schema.go | 10 +++++++++- pkg/codegen/test_spec.yaml | 30 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index ff3c86d9ba..4920c72e49 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -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") diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index f7b6fd6ac1..25f34de38a 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -602,6 +602,9 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem if err != nil { return fmt.Errorf("error generating type for array: %w", err) } + + var itemPrefix string + 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 @@ -618,8 +621,13 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem arrayType.RefType = typeName } + + if arrayType.OAPISchema != nil && arrayType.OAPISchema.Nullable { + itemPrefix = "*" + } + outSchema.ArrayType = &arrayType - outSchema.GoType = "[]" + arrayType.TypeDecl() + outSchema.GoType = "[]" + itemPrefix + arrayType.TypeDecl() outSchema.AdditionalTypes = arrayType.AdditionalTypes outSchema.Properties = arrayType.Properties outSchema.DefineViaAlias = true 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 ] From 4b72bdb6df43b9ddf58625916724a5cf23b80f34 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 17 Feb 2026 07:11:54 -0800 Subject: [PATCH 180/293] feat: add Valid() method to generated enum types (#2227) * feat: add Valid() method to generated enum types Generate a Valid() bool method on each enum type that returns true when the receiver matches one of the defined enum constants and false otherwise. This lets callers validate enum values at runtime with a simple method call instead of hand-writing switch statements. This is default-on because it only adds a new method to an already generated type -- existing code that does not call Valid() is completely unaffected, so this should be very unlikely to break anything. Co-Authored-By: Claude Opus 4.6 * Reduce complexity in enum validation It turns out we don't need a sorted map of names, since we have the same thing already present on the template context in a different way. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- internal/test/components/components.gen.go | 162 ++++++++++++++++++ .../externalref/petstore/externalref.gen.go | 42 +++++ .../test/issues/issue-1189/issue1189.gen.go | 36 ++++ .../test/issues/issue-1397/issue1397.gen.go | 12 ++ internal/test/issues/issue-832/issue.gen.go | 16 ++ .../issue-illegal_enum_names/issue.gen.go | 28 +++ internal/test/parameters/parameters.gen.go | 12 ++ internal/test/schemas/schemas.gen.go | 12 ++ internal/test/server/server.gen.go | 12 ++ pkg/codegen/templates/constants.tmpl | 10 ++ 10 files changed, 342 insertions(+) diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index 95257707b1..0bfc1747e6 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"` diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index 33852217e1..e8102f0d28 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -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"` diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index c1a869ad98..c6e0579fd5 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -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"` diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index 2463641eb1..11bc883db2 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -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 diff --git a/internal/test/issues/issue-832/issue.gen.go b/internal/test/issues/issue-832/issue.gen.go index 0aa74f232e..4a5aa56a3d 100644 --- a/internal/test/issues/issue-832/issue.gen.go +++ b/internal/test/issues/issue-832/issue.gen.go @@ -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"` 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 8f907486cf..0c29ab71eb 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -34,6 +34,34 @@ const ( 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 diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 630770731a..47c98a774e 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -27,6 +27,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"` diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 1a7f9e61b7..c46358f7f6 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -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{} diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go index e360916b3a..b2468c75b4 100644 --- a/internal/test/server/server.gen.go +++ b/internal/test/server/server.gen.go @@ -19,6 +19,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"` diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index 8fad8764c4..1c8cbd4922 100644 --- a/pkg/codegen/templates/constants.tmpl +++ b/pkg/codegen/templates/constants.tmpl @@ -12,4 +12,14 @@ const ( {{$name}} {{$Enum.TypeName}} = {{$Enum.ValueWrapper}}{{$value}}{{$Enum.ValueWrapper -}} {{end}} ) + +// 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}} From b00a8ea7648caac4345b9f1fe5c1dd30dd0ef016 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Sat, 21 Feb 2026 11:56:47 +0800 Subject: [PATCH 181/293] style(gofix): Apply `go fix` (#2229) Signed-off-by: Gaiaz Iusipov --- cmd/oapi-codegen/oapi-codegen.go | 9 +++++---- pkg/codegen/extension.go | 26 +++++++++++++------------- pkg/codegen/extension_test.go | 4 ++-- pkg/codegen/merge_schemas.go | 2 +- pkg/codegen/operations.go | 2 +- pkg/codegen/prune.go | 10 +++------- pkg/codegen/schema.go | 8 ++++---- pkg/codegen/utils.go | 31 +++++++++++-------------------- pkg/codegen/utils_test.go | 2 +- 9 files changed, 41 insertions(+), 53 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 78bea5b1e3..a3e43498c4 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -29,7 +29,7 @@ import ( "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" } @@ -272,12 +272,13 @@ func main() { } if warnings := opts.Generate.Warnings(); len(warnings) > 0 { - out := "WARNING: A number of warning(s) were returned when validating the GenerateOptions:" + var out strings.Builder + out.WriteString("WARNING: A number of warning(s) were returned when validating the GenerateOptions:") for k, v := range warnings { - out += "\n- " + k + ": " + v + out.WriteString("\n- " + k + ": " + v) } - _, _ = fmt.Fprint(os.Stderr, out) + _, _ = fmt.Fprint(os.Stderr, out.String()) } // If the user asked to output configuration, output it to stdout and exit diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index 579d8a17c9..6bc6bff144 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -29,7 +29,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) @@ -37,11 +37,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) @@ -49,11 +49,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) @@ -61,7 +61,7 @@ func extParseOmitEmpty(extPropValue interface{}) (bool, error) { return omitEmpty, nil } -func extParseOmitZero(extPropValue interface{}) (bool, error) { +func extParseOmitZero(extPropValue any) (bool, error) { omitZero, ok := extPropValue.(bool) if !ok { return false, fmt.Errorf("failed to convert type: %T", extPropValue) @@ -69,8 +69,8 @@ func extParseOmitZero(extPropValue interface{}) (bool, error) { return omitZero, nil } -func extExtraTags(extPropValue interface{}) (map[string]string, error) { - tagsI, ok := extPropValue.(map[string]interface{}) +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) } @@ -85,7 +85,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) @@ -93,8 +93,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) } @@ -109,11 +109,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/merge_schemas.go b/pkg/codegen/merge_schemas.go index 04e7b2fa2b..39c499c7da 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -87,7 +87,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) { func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) { var result openapi3.Schema - result.Extensions = make(map[string]interface{}) + result.Extensions = make(map[string]any) for k, v := range s1.Extensions { result.Extensions[k] = v } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index e4d9784702..1743d270ea 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -1067,7 +1067,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/prune.go b/pkg/codegen/prune.go index 0d3a889747..e97ba3469e 100644 --- a/pkg/codegen/prune.go +++ b/pkg/codegen/prune.go @@ -2,23 +2,19 @@ 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 + return slices.Contains(list, a) } type RefWrapper struct { Ref string HasValue bool - SourceRef interface{} + SourceRef any } func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 25f34de38a..cc14db731f 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -102,7 +102,7 @@ type Property struct { ReadOnly bool WriteOnly bool NeedsFormTag bool - Extensions map[string]interface{} + Extensions map[string]any Deprecated bool } @@ -270,11 +270,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 + var method strings.Builder for _, part := range strings.Split(string(u), `.`) { - method += UppercaseFirstCharacter(part) + method.WriteString(UppercaseFirstCharacter(part)) } - return method + return method.String() } func PropertiesEqual(a, b Property) bool { diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 79e274f7ee..549d5cffa3 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -20,6 +20,7 @@ import ( "net/url" "reflect" "regexp" + "slices" "sort" "strconv" "strings" @@ -205,7 +206,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 +225,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 @@ -407,12 +408,7 @@ func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) { // 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 + return slices.Contains(array, str) } // RefPathToObjName returns the name of referenced object without changes. @@ -1074,7 +1070,7 @@ func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) { goTypeImportExt := v.Value.Extensions[extPropGoImport] - importI, ok := goTypeImportExt.(map[string]interface{}) + importI, ok := goTypeImportExt.(map[string]any) if !ok { return nil, fmt.Errorf("failed to convert type: %T", goTypeImportExt) } @@ -1126,12 +1122,7 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool { } func sliceContains[E comparable](s []E, v E) bool { - for _, ss := range s { - if ss == v { - return true - } - } - return false + return slices.Contains(s, v) } // FixDuplicateTypeNames renames duplicate type names. diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index f204fc50c8..3f9e0e8b76 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}, }, } } From eb9b3830c17782f8a022ded6b43c160d8dbf6b01 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 24 Feb 2026 06:59:30 -0800 Subject: [PATCH 182/293] Configure Greptile code review (#2236) Don't automatically review each PR, users can request a code review via tagging @greptileai Exclude generated files from code reviews. It's pointless. --- greptile.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 greptile.json diff --git a/greptile.json b/greptile.json new file mode 100644 index 0000000000..bc3cc79fc0 --- /dev/null +++ b/greptile.json @@ -0,0 +1,4 @@ +{ + "skipReview": "AUTOMATIC", + "ignorePatterns": "**/*.gen.go" +} From a14bfbb47559fa19046fa80793feb1cc4c64e4c7 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 24 Feb 2026 14:16:19 +0000 Subject: [PATCH 183/293] fix(server-urls): restore generation of constants This fixes a regression from 59fb0e86773ac572016038c9cd21569de8d6a1b2. --- pkg/codegen/templates/server-urls.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl index 1c60e796b1..3f1fdfe734 100644 --- a/pkg/codegen/templates/server-urls.tmpl +++ b/pkg/codegen/templates/server-urls.tmpl @@ -2,6 +2,7 @@ {{ if eq 0 (len .OAPISchema.Variables) }} {{/* URLs without variables are straightforward, so we'll create them a constant */}} // {{ .GoName }} defines the Server URL for {{ if len .OAPISchema.Description }}{{ .OAPISchema.Description }}{{ else }}{{ .OAPISchema.URL }}{{ end }} +const {{ .GoName}} = "{{ .OAPISchema.URL }}" {{ else }} {{/* URLs with variables are not straightforward, as we may need multiple types, and so will model them as a function */}} From 918ff57a9d9852df18558516b13678af7f676fc7 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 24 Feb 2026 13:52:05 +0000 Subject: [PATCH 184/293] fix(templates/client): correctly nil check query parameters As a fix similar to c4ba545dc7f4c67d796d7fbde1203b775f3a3056, we had cases where the global `prefer-skip-optional-pointer` could lead to not nil checking when we should have been. The previous behaviour would lead to incorrectly converting i.e. `user_ids=nil` to `user_ids[]=`, which is not correct. To do this, we can add the same helper functions that we have elsewhere. --- .../test/issues/issue-2031/prefer/config.yaml | 7 + .../test/issues/issue-2031/prefer/generate.go | 3 + .../issues/issue-2031/prefer/issue2031.gen.go | 251 ++++++++++++++++++ .../issue-2031/prefer/issue2031_test.go | 63 +++++ .../issues/issue-2031/prefer/openapi.yaml | 17 ++ pkg/codegen/operations.go | 17 ++ pkg/codegen/templates/client.tmpl | 6 +- 7 files changed, 361 insertions(+), 3 deletions(-) create mode 100644 internal/test/issues/issue-2031/prefer/config.yaml create mode 100644 internal/test/issues/issue-2031/prefer/generate.go create mode 100644 internal/test/issues/issue-2031/prefer/issue2031.gen.go create mode 100644 internal/test/issues/issue-2031/prefer/issue2031_test.go create mode 100644 internal/test/issues/issue-2031/prefer/openapi.yaml 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..64b30f3515 --- /dev/null +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -0,0 +1,251 @@ +// 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 := queryURL.Query() + + if params.UserIds != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "user_ids[]", runtime.ParamLocationQuery, params.UserIds); 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) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", 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 +} + +// 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 +} + +// 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/pkg/codegen/operations.go b/pkg/codegen/operations.go index 1743d270ea..e2a12d7117 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -44,6 +44,23 @@ 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 +// Will return true if the OpenAPI `type` is: +// - `array` +func (pd ParameterDefinition) ZeroValueIsNil() bool { + if pd.Schema.OAPISchema == nil { + return false + } + + return pd.Schema.OAPISchema.Type.Is("array") +} + // 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"' diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 822e11097a..d219432e29 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -197,7 +197,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr if params != nil { queryValues := queryURL.Query() {{range $paramIdx, $param := .QueryParams}} - {{if .HasOptionalPointer}} if params.{{.GoName}} != nil { {{end}} + {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}} {{if .IsPassThrough}} queryValues.Add("{{.ParamName}}", {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}) {{end}} @@ -210,7 +210,7 @@ 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 .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil { + if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if and .RequiresNilCheck .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -222,7 +222,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr } } {{end}} - {{if .HasOptionalPointer}}}{{end}} + {{if .RequiresNilCheck}}}{{end}} {{end}} queryURL.RawQuery = queryValues.Encode() } From 12a9b208ed10d408c4d0c82a5f1297c25a1a2322 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 24 Feb 2026 08:37:49 -0800 Subject: [PATCH 185/293] fix: support x-oapi-codegen-extra-tags on parameter schemas (#2232) (#2235) When x-oapi-codegen-extra-tags was placed on the schema inside a parameter definition (rather than on the parameter itself), the extension was silently ignored. This happened because GenerateParamsTypes only read parameter-level extensions, not schema-level ones. Merge extensions from both the parameter and its schema when building the Params struct, with parameter-level extensions taking precedence. Co-authored-by: Claude Opus 4.6 --- internal/test/issues/issue-2232/config.yaml | 5 + internal/test/issues/issue-2232/generate.go | 3 + .../test/issues/issue-2232/issue2232.gen.go | 260 ++++++++++++++++++ .../test/issues/issue-2232/issue2232_test.go | 41 +++ internal/test/issues/issue-2232/spec.yaml | 46 ++++ pkg/codegen/operations.go | 13 +- 6 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 internal/test/issues/issue-2232/config.yaml create mode 100644 internal/test/issues/issue-2232/generate.go create mode 100644 internal/test/issues/issue-2232/issue2232.gen.go create mode 100644 internal/test/issues/issue-2232/issue2232_test.go create mode 100644 internal/test/issues/issue-2232/spec.yaml 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..e795e7ad72 --- /dev/null +++ b/internal/test/issues/issue-2232/issue2232.gen.go @@ -0,0 +1,260 @@ +//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 ( + "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 + + // Parameter object where we will unmarshal all parameters from the context + var params GetEndpointParams + + // ------------- Required query parameter "env_param_level" ------------- + + if paramValue := r.URL.Query().Get("env_param_level"); paramValue != "" { + + } else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_param_level"}) + return + } + + err = runtime.BindQueryParameter("form", true, true, "env_param_level", r.URL.Query(), ¶ms.EnvParamLevel) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_param_level", Err: err}) + return + } + + // ------------- Required query parameter "env_schema_level" ------------- + + if paramValue := r.URL.Query().Get("env_schema_level"); paramValue != "" { + + } else { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_schema_level"}) + return + } + + err = runtime.BindQueryParameter("form", true, true, "env_schema_level", r.URL.Query(), ¶ms.EnvSchemaLevel) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_schema_level", Err: err}) + return + } + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +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("GET "+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/pkg/codegen/operations.go b/pkg/codegen/operations.go index e2a12d7117..62ec2e085e 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -942,13 +942,24 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { Schema: param.Schema, }) } + // Merge extensions from the schema level and the parameter level. + // Parameter-level extensions take precedence over schema-level ones. + extensions := make(map[string]any) + if param.Spec.Schema != nil && param.Spec.Schema.Value != nil { + for k, v := range param.Spec.Schema.Value.Extensions { + extensions[k] = v + } + } + for k, v := range param.Spec.Extensions { + extensions[k] = v + } 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) } From 99eadbe66e960f69dcffd9296ccea7809c3e56dd Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Tue, 24 Feb 2026 18:46:07 +0000 Subject: [PATCH 186/293] fix(codegen): generate `nullable.Nullable` in arrays As a follow-up to #2185, we can make sure we generate a Nullable type if required to do so. --- internal/test/issues/issue-2185/config.yaml | 8 ++++++++ internal/test/issues/issue-2185/generate.go | 3 +++ .../test/issues/issue-2185/issue2185.gen.go | 13 +++++++++++++ .../test/issues/issue-2185/issue2185_test.go | 19 +++++++++++++++++++ internal/test/issues/issue-2185/spec.yaml | 15 +++++++++++++++ pkg/codegen/schema.go | 11 +++++++---- 6 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 internal/test/issues/issue-2185/config.yaml create mode 100644 internal/test/issues/issue-2185/generate.go create mode 100644 internal/test/issues/issue-2185/issue2185.gen.go create mode 100644 internal/test/issues/issue-2185/issue2185_test.go create mode 100644 internal/test/issues/issue-2185/spec.yaml 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/pkg/codegen/schema.go b/pkg/codegen/schema.go index cc14db731f..ea6e137473 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -603,8 +603,6 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem return fmt.Errorf("error generating type for array: %w", err) } - var itemPrefix string - 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 @@ -622,12 +620,17 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem arrayType.RefType = typeName } + typeDeclaration := arrayType.TypeDecl() if arrayType.OAPISchema != nil && arrayType.OAPISchema.Nullable { - itemPrefix = "*" + if globalState.options.OutputOptions.NullableType { + typeDeclaration = "nullable.Nullable[" + typeDeclaration + "]" + } else { + typeDeclaration = "*" + typeDeclaration + } } outSchema.ArrayType = &arrayType - outSchema.GoType = "[]" + itemPrefix + arrayType.TypeDecl() + outSchema.GoType = "[]" + typeDeclaration outSchema.AdditionalTypes = arrayType.AdditionalTypes outSchema.Properties = arrayType.Properties outSchema.DefineViaAlias = true From d567e49b4a4c82e3ab43a23f232bebbbc05cf161 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 26 Feb 2026 06:46:01 -0800 Subject: [PATCH 187/293] fix: add omitempty to optional nullable fields (#2221) Fixes #2091 The `omitempty` JSON tag was not being added to optional nullable fields. The condition `!p.Nullable && shouldOmitEmpty` explicitly prevented any nullable field from receiving `omitempty`, even when the field was optional (not required). This contradicted the documented behavior. The fix removes the `!p.Nullable` guard so nullable fields follow the same `omitempty` rules as non-nullable fields. The special-case exception for the `nullable-type` output option is no longer needed since the logic is now uniform. Note: `x-go-type-skip-optional-pointer: true` on a nullable field suppresses the pointer (generating `string` instead of `*string`) but still correctly receives `omitempty` when the field is optional. Whether skip-optional-pointer should be allowed to suppress the pointer on nullable fields is a separate concern. Co-authored-by: Claude Opus 4.6 --- .../test/issues/issue-1039/defaultbehaviour/types.gen.go | 6 +++--- internal/test/schemas/schemas.gen.go | 2 +- pkg/codegen/codegen_test.go | 4 ++-- pkg/codegen/schema.go | 6 +----- 4 files changed, 7 insertions(+), 11 deletions(-) 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/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index c46358f7f6..f1afb25b19 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -92,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"` } diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 4920c72e49..b7b3184c3c 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -117,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\"`") diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index ea6e137473..067d03955d 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -734,11 +734,7 @@ func GenFieldsFromProperties(props []Property) []string { shouldOmitEmpty := (!p.Required || p.ReadOnly || p.WriteOnly) && (!p.Required || !p.ReadOnly || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer) - omitEmpty := !p.Nullable && shouldOmitEmpty - - if p.Nullable && globalState.options.OutputOptions.NullableType { - omitEmpty = shouldOmitEmpty - } + omitEmpty := shouldOmitEmpty omitZero := false From a701ab9d9965e04dcdfb88f80373057f019b6061 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 26 Feb 2026 07:50:21 +0000 Subject: [PATCH 188/293] chore(renovate): add module path to security updates So it's clearer when the PR is for `examples/` or `internal/test/`, similar to regular PRs. --- renovate.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/renovate.json b/renovate.json index 85610cfaa1..685190682d 100644 --- a/renovate.json +++ b/renovate.json @@ -6,6 +6,9 @@ "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.", From a7de76c97726b529403b82141dd236c89f514cf0 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 26 Feb 2026 07:53:31 +0000 Subject: [PATCH 189/293] chore(renovate): override test-only dependencies' label So they don't get pulled into Release Drafter releases. --- renovate.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/renovate.json b/renovate.json index 685190682d..3af37f23db 100644 --- a/renovate.json +++ b/renovate.json @@ -18,6 +18,16 @@ "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": [ From 8260a75148c2ee4b1fa5c45867e95ab10dbe05ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:57 +0000 Subject: [PATCH 190/293] chore(deps): update dessant/label-actions action to v5 (.github/workflows) --- .github/workflows/label-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml index ff95f0a0cc..9e854222e2 100644 --- a/.github/workflows/label-actions.yml +++ b/.github/workflows/label-actions.yml @@ -18,6 +18,6 @@ jobs: reaction: runs-on: ubuntu-latest steps: - - uses: dessant/label-actions@102faf474a544be75fbaf4df54e73d3c515a0e65 # v4.0.1 + - uses: dessant/label-actions@9e5fd757ffe1e065abf55e9f74d899dbe012922a # v5.0.0 with: github-token: ${{ github.token }} From c184310cb923e5182c637477dcb7349dd319fb47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:58:55 +0000 Subject: [PATCH 191/293] chore(deps): update actions/upload-artifact action to v7 (.github/workflows) --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index dcb2390b74..9aee855bfb 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: SARIF file path: results.sarif From 109fbfa777dde0ff1b8c9d0e960358d9cd450b6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:22 +0000 Subject: [PATCH 192/293] chore(deps): update release-drafter/release-drafter action to v6.2.0 (.github/workflows) --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 5f2ab3f3cd..7b03a27d7a 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@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0 + - uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0 with: name: next tag: next From 33cd677de3459f1c2dd3f957e54920a3f16ef62b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:48 +0000 Subject: [PATCH 193/293] chore(deps): update actions/checkout action to v6 (.github/workflows) --- .github/workflows/ci.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b21f3f88ee..346cb17236 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - "oldstable" steps: - name: Check out source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 9aee855bfb..c7bd46f865 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -20,7 +20,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false show-progress: false From 3f9222e489235ed87fd4e6b742f25f2ec3b7d695 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:11 +0000 Subject: [PATCH 194/293] chore(deps): update actions/setup-go action to v6.3.0 (.github/workflows) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 346cb17236..9a010b440e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version: ${{ matrix.version }} From 6f6e243e3263793ca5b45d251b190f182b0ceece Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:15 +0000 Subject: [PATCH 195/293] chore(deps): update github/codeql-action action to v4.32.4 (.github/workflows) --- .github/workflows/govulncheck.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 0e4f8a1451..6be0b7d905 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -29,7 +29,7 @@ jobs: # ... 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@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: sarif_file: govulncheck.sarif category: govulncheck diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index c7bd46f865..459dd315e0 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,6 +41,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: sarif_file: results.sarif From 890e8de02b828b191d1d239ffba2be136269ca9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:14:19 +0000 Subject: [PATCH 196/293] chore(deps): update module github.com/golangci/golangci-lint to v2.10.1 (makefile) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 069527cf0e..f09a336c11 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) v2.6.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v2.10.1 .PHONY: tools tools: $(GOBIN)/golangci-lint From 28d008361507817aa69e261cadf2f3bbfd048cf5 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 26 Feb 2026 14:17:49 -0800 Subject: [PATCH 197/293] Update github.com/oapi-codegen/runtime to v1.2.0 Co-Authored-By: Claude Opus 4.6 --- examples/go.mod | 8 +- examples/go.sum | 16 ++-- examples/petstore-expanded/fiber/go.mod | 4 +- examples/petstore-expanded/fiber/go.sum | 12 +-- examples/petstore-expanded/stdhttp/go.mod | 6 +- examples/petstore-expanded/stdhttp/go.sum | 16 ++-- internal/test/go.mod | 41 +++++----- internal/test/go.sum | 95 ++++++++++------------ internal/test/strict-server/fiber/go.mod | 2 +- internal/test/strict-server/fiber/go.sum | 8 +- internal/test/strict-server/stdhttp/go.mod | 4 +- internal/test/strict-server/stdhttp/go.sum | 12 +-- 12 files changed, 110 insertions(+), 114 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 89ce0af263..04cb27ccd2 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,7 +6,7 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( github.com/getkin/kin-openapi v0.133.0 - github.com/gin-gonic/gin v1.10.0 + github.com/gin-gonic/gin v1.10.1 github.com/go-chi/chi/v5 v5.0.10 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 @@ -18,7 +18,7 @@ require ( github.com/oapi-codegen/iris-middleware v1.0.5 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/runtime v1.2.0 github.com/oapi-codegen/testutil v1.0.0 github.com/stretchr/testify v1.11.1 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 @@ -52,7 +52,7 @@ require ( 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/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -87,7 +87,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect - github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sirupsen/logrus v1.9.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect github.com/tdewolff/minify/v2 v2.12.9 // indirect diff --git a/examples/go.sum b/examples/go.sum index d7a256ee0e..7a8759d76b 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -56,8 +56,8 @@ github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/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= @@ -92,8 +92,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4= +github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/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= @@ -201,8 +201,8 @@ github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq 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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -239,8 +239,9 @@ github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiy github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= 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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= +github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= @@ -361,6 +362,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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-20220715151400-c0bba94af5f8/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= diff --git a/examples/petstore-expanded/fiber/go.mod b/examples/petstore-expanded/fiber/go.mod index a93bf57445..848ae29799 100644 --- a/examples/petstore-expanded/fiber/go.mod +++ b/examples/petstore-expanded/fiber/go.mod @@ -10,7 +10,7 @@ require ( github.com/getkin/kin-openapi v0.133.0 github.com/gofiber/fiber/v2 v2.52.11 github.com/oapi-codegen/fiber-middleware v1.0.2 - github.com/oapi-codegen/runtime v1.1.0 + github.com/oapi-codegen/runtime v1.2.0 github.com/stretchr/testify v1.11.1 ) @@ -46,7 +46,7 @@ require ( golang.org/x/mod v0.23.0 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/examples/petstore-expanded/fiber/go.sum b/examples/petstore-expanded/fiber/go.sum index 62ff2f51fd..4d328b9424 100644 --- a/examples/petstore-expanded/fiber/go.sum +++ b/examples/petstore-expanded/fiber/go.sum @@ -77,8 +77,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI= github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg= -github.com/oapi-codegen/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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -117,8 +117,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= @@ -174,8 +174,8 @@ 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 536fc339df..cd3edaec36 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -8,7 +8,7 @@ require ( github.com/getkin/kin-openapi v0.133.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/runtime v1.2.0 github.com/oapi-codegen/testutil v1.0.0 github.com/stretchr/testify v1.11.1 ) @@ -19,7 +19,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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/google/uuid v1.5.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -34,7 +34,7 @@ require ( github.com/woodsbury/decimal128 v1.3.0 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.30.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 index 7bf494f54d..33f9b11fbb 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -39,8 +39,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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/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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -64,8 +64,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -103,8 +103,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= @@ -152,8 +152,8 @@ 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 4d9e591610..f027d757f8 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -6,15 +6,15 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( github.com/getkin/kin-openapi v0.133.0 - github.com/gin-gonic/gin v1.9.1 + github.com/gin-gonic/gin v1.10.1 github.com/go-chi/chi/v5 v5.0.10 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.5.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/labstack/echo/v4 v4.11.4 github.com/oapi-codegen/nullable v1.0.1 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.1.0 + github.com/oapi-codegen/runtime v1.2.0 github.com/oapi-codegen/testutil v1.0.0 github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 @@ -29,24 +29,25 @@ require ( github.com/andybalholm/brotli v1.0.5 // 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/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/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/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/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/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/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -57,32 +58,32 @@ require ( 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/cpuid/v2 v2.2.7 // indirect + github.com/labstack/gommon v0.4.2 // 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-isatty v0.0.20 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect - github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sirupsen/logrus v1.9.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.2 // 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/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect @@ -90,16 +91,16 @@ require ( github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/yosssi/ace v0.0.5 // indirect - golang.org/x/arch v0.4.0 // indirect + golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.33.0 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/net v0.35.0 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.30.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/test/go.sum b/internal/test/go.sum index 994b539a63..2d726a40f9 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -20,19 +20,17 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP 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/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/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/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/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= @@ -49,14 +47,14 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -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/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/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= @@ -69,8 +67,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o 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-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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -91,8 +89,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4= +github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/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= @@ -103,8 +101,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD 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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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/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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -139,8 +137,8 @@ github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwf 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/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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -149,23 +147,21 @@ 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +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/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-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/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -183,8 +179,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -203,8 +199,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -219,8 +215,9 @@ github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiy github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= 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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= +github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= @@ -240,8 +237,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/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.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA= @@ -252,11 +249,10 @@ github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0= github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= @@ -284,8 +280,8 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf 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= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 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= @@ -326,11 +322,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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= @@ -344,8 +338,8 @@ 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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -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/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/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= @@ -364,8 +358,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= @@ -384,7 +378,6 @@ 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= diff --git a/internal/test/strict-server/fiber/go.mod b/internal/test/strict-server/fiber/go.mod index add341aacf..a5442edf9d 100644 --- a/internal/test/strict-server/fiber/go.mod +++ b/internal/test/strict-server/fiber/go.mod @@ -12,7 +12,7 @@ require ( github.com/getkin/kin-openapi v0.133.0 github.com/gofiber/fiber/v2 v2.52.11 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/runtime v1.2.0 github.com/oapi-codegen/testutil v1.0.0 github.com/stretchr/testify v1.11.1 ) diff --git a/internal/test/strict-server/fiber/go.sum b/internal/test/strict-server/fiber/go.sum index f585043c1b..0d990d7990 100644 --- a/internal/test/strict-server/fiber/go.sum +++ b/internal/test/strict-server/fiber/go.sum @@ -73,8 +73,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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/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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -115,8 +115,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index b56e4799a0..4e0463b0c5 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( github.com/getkin/kin-openapi v0.133.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/runtime v1.2.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) @@ -21,7 +21,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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/google/uuid v1.5.0 // 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 diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 880c5ff529..57cd609934 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -39,8 +39,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/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/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -60,8 +60,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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/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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -99,8 +99,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= From 15fc5363ceba4fbb246d7b39ea76ac0b9a49216a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 26 Feb 2026 14:50:41 -0800 Subject: [PATCH 198/293] fix: pass OpenAPI type/format to runtime parameter binding and styling functions Update all parameter binding and styling call sites across all server templates and the client template to pass the OpenAPI schema Type and Format through to the runtime library. This enables the runtime (v1.2.0+) to correctly handle format: byte parameters by base64-encoding/decoding the value, instead of incorrectly treating []byte as a generic []uint8 slice. Changes: - Add SchemaType() and SchemaFormat() helper methods to ParameterDefinition - Update BindStyledParameterWithOptions calls in all 7 server templates (echo, chi, stdhttp, gin, gorilla, fiber, iris) to include Type/Format - Replace BindQueryParameter with BindQueryParameterWithOptions in all 7 server templates, passing Type/Format via options struct - Replace StyleParamWithLocation with StyleParamWithOptions in client.tmpl, passing Type/Format via options struct - Regenerate all test fixtures Requires a minimum of runtime v1.2.0. Closes #173 Closes #2248 Co-Authored-By: Claude Opus 4.6 --- .../fiber/api/petstore-server.gen.go | 8 +- .../stdhttp/api/petstore.gen.go | 8 +- internal/test/any_of/param/param.gen.go | 4 +- internal/test/cookies/cookies.gen.go | 4 +- internal/test/issues/issue-1180/issue.gen.go | 4 +- .../issue-1378/bionicle/bionicle.gen.go | 2 +- .../issue-1378/fooservice/fooservice.gen.go | 2 +- .../issues/issue-2031/prefer/issue2031.gen.go | 2 +- .../test/issues/issue-2232/issue2232.gen.go | 6 +- internal/test/issues/issue-312/issue.gen.go | 4 +- .../issue-grab_import_names/issue.gen.go | 8 +- .../name_normalizer.gen.go | 4 +- .../name_normalizer.gen.go | 4 +- .../name_normalizer.gen.go | 4 +- .../to-camel-case/name_normalizer.gen.go | 4 +- .../unset/name_normalizer.gen.go | 4 +- internal/test/parameters/parameters.gen.go | 148 +++++++++--------- internal/test/schemas/schemas.gen.go | 16 +- internal/test/server/server.gen.go | 20 +-- internal/test/strict-server/chi/server.gen.go | 6 +- .../test/strict-server/client/client.gen.go | 6 +- .../test/strict-server/echo/server.gen.go | 6 +- .../test/strict-server/fiber/server.gen.go | 6 +- internal/test/strict-server/gin/server.gen.go | 6 +- .../test/strict-server/gorilla/server.gen.go | 6 +- .../test/strict-server/iris/server.gen.go | 6 +- .../test/strict-server/stdhttp/server.gen.go | 6 +- pkg/codegen/operations.go | 20 +++ pkg/codegen/templates/chi/chi-middleware.tmpl | 8 +- pkg/codegen/templates/client.tmpl | 8 +- pkg/codegen/templates/echo/echo-wrappers.tmpl | 8 +- .../templates/fiber/fiber-middleware.tmpl | 8 +- pkg/codegen/templates/gin/gin-wrappers.tmpl | 8 +- .../templates/gorilla/gorilla-middleware.tmpl | 8 +- .../templates/iris/iris-middleware.tmpl | 8 +- .../stdhttp/std-http-middleware.tmpl | 8 +- 36 files changed, 204 insertions(+), 184 deletions(-) diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go index 5b01b84a07..a5c583ef06 100644 --- a/examples/petstore-expanded/fiber/api/petstore-server.gen.go +++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go @@ -56,14 +56,14 @@ 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()) } @@ -85,7 +85,7 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *fiber.Ctx) error { // ------------- 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{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()) } @@ -101,7 +101,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(c *fiber.Ctx) error { // ------------- 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{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()) } diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index 3f99776250..4f0c52be9d 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -96,7 +96,7 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque // ------------- 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}) return @@ -104,7 +104,7 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque // ------------- 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}) return @@ -143,7 +143,7 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ // ------------- 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 @@ -168,7 +168,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re // ------------- 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 diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 3378ae3da1..483228d045 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -286,7 +286,7 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err if params.Test != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -302,7 +302,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "test2", *params.Test2, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err diff --git a/internal/test/cookies/cookies.gen.go b/internal/test/cookies/cookies.gen.go index 5168bbd153..4e9b6139ec 100644 --- a/internal/test/cookies/cookies.gen.go +++ b/internal/test/cookies/cookies.gen.go @@ -58,7 +58,7 @@ func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.R if cookie, err = r.Cookie("authId"); err == nil { var value string - err = runtime.BindStyledParameterWithOptions("simple", "authId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false}) + err = runtime.BindStyledParameterWithOptions("simple", "authId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "authId", Err: err}) return @@ -73,7 +73,7 @@ func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.R if cookie, err = r.Cookie("serverId"); err == nil { var value string - err = runtime.BindStyledParameterWithOptions("simple", "serverId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false}) + err = runtime.BindStyledParameterWithOptions("simple", "serverId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "serverId", Err: err}) return diff --git a/internal/test/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index cc675b96da..26e358477a 100644 --- a/internal/test/issues/issue-1180/issue.gen.go +++ b/internal/test/issues/issue-1180/issue.gen.go @@ -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 } @@ -254,7 +254,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)) } diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index 4af1127555..863c5fd380 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -54,7 +54,7 @@ func (siw *ServerInterfaceWrapper) GetBionicleName(w http.ResponseWriter, r *htt // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) return diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index 6645be355e..d076409c14 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -47,7 +47,7 @@ func (siw *ServerInterfaceWrapper) GetBionicleName(w http.ResponseWriter, r *htt // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) return diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go index 64b30f3515..6144c0b4be 100644 --- a/internal/test/issues/issue-2031/prefer/issue2031.gen.go +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -132,7 +132,7 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err if params.UserIds != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "user_ids[]", runtime.ParamLocationQuery, params.UserIds); err != 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err diff --git a/internal/test/issues/issue-2232/issue2232.gen.go b/internal/test/issues/issue-2232/issue2232.gen.go index e795e7ad72..1820ba5f29 100644 --- a/internal/test/issues/issue-2232/issue2232.gen.go +++ b/internal/test/issues/issue-2232/issue2232.gen.go @@ -94,7 +94,7 @@ func (siw *ServerInterfaceWrapper) GetEndpoint(w http.ResponseWriter, r *http.Re return } - err = runtime.BindQueryParameter("form", true, true, "env_param_level", r.URL.Query(), ¶ms.EnvParamLevel) + err = runtime.BindQueryParameterWithOptions("form", true, true, "env_param_level", r.URL.Query(), ¶ms.EnvParamLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_param_level", Err: err}) return @@ -109,7 +109,7 @@ func (siw *ServerInterfaceWrapper) GetEndpoint(w http.ResponseWriter, r *http.Re return } - err = runtime.BindQueryParameter("form", true, true, "env_schema_level", r.URL.Query(), ¶ms.EnvSchemaLevel) + err = runtime.BindQueryParameterWithOptions("form", true, true, "env_schema_level", r.URL.Query(), ¶ms.EnvSchemaLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_schema_level", Err: err}) return @@ -117,7 +117,7 @@ func (siw *ServerInterfaceWrapper) GetEndpoint(w http.ResponseWriter, r *http.Re // ------------- 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: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) return diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index f0285c071f..1686dac248 100644 --- a/internal/test/issues/issue-312/issue.gen.go +++ b/internal/test/issues/issue-312/issue.gen.go @@ -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 } @@ -440,7 +440,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)) } 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..99bfcd9548 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -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 } @@ -304,7 +304,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 +319,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)) } 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 index b04b92ae87..8d02762813 100644 --- 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 @@ -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 } @@ -368,7 +368,7 @@ func (siw *ServerInterfaceWrapper) GetHTTPPet(w http.ResponseWriter, r *http.Req // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err}) return 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..206ddbf64d 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 @@ -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 } @@ -368,7 +368,7 @@ func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Req // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err}) return 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..6cf9d6e7fe 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 @@ -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 } @@ -368,7 +368,7 @@ func (siw *ServerInterfaceWrapper) GetHTTPPet(w http.ResponseWriter, r *http.Req // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err}) return 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..e34d1c4663 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 @@ -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 } @@ -368,7 +368,7 @@ func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Req // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err}) return 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..17f65ad9ee 100644 --- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go +++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go @@ -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 } @@ -368,7 +368,7 @@ func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Req // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err}) return diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 47c98a774e..5821715fc2 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -605,7 +605,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 } @@ -620,7 +620,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 } @@ -635,7 +635,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 } @@ -650,7 +650,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 } @@ -665,7 +665,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 } @@ -680,7 +680,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 } @@ -712,7 +712,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 } @@ -751,7 +751,7 @@ func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Reques if params.EnumPathParam != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -805,7 +805,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 } @@ -816,7 +816,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 } @@ -827,7 +827,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 } @@ -838,7 +838,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 } @@ -849,7 +849,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 } @@ -860,7 +860,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 } @@ -884,7 +884,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 } @@ -903,7 +903,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 } @@ -937,7 +937,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 } @@ -971,7 +971,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 } @@ -1005,7 +1005,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 } @@ -1039,7 +1039,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 } @@ -1073,7 +1073,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 } @@ -1107,7 +1107,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 } @@ -1141,7 +1141,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 } @@ -1222,7 +1222,7 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http. if params != nil { queryValues := queryURL.Query() - if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1269,7 +1269,7 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if params.Ea != nil { - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1285,7 +1285,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1301,7 +1301,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1317,7 +1317,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1333,7 +1333,7 @@ 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 { + 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1349,7 +1349,7 @@ 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 { + 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1365,7 +1365,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "ps", *params.Ps, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1391,7 +1391,7 @@ 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 { + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1422,7 +1422,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 } @@ -1456,7 +1456,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 } @@ -1490,7 +1490,7 @@ func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Requ 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 } @@ -1524,7 +1524,7 @@ func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Requ 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: "", Format: ""}) if err != nil { return nil, err } @@ -1558,7 +1558,7 @@ func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, er 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 } @@ -2788,7 +2788,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2799,7 +2799,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2810,7 +2810,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2821,7 +2821,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2832,7 +2832,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2843,7 +2843,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2870,7 +2870,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error { 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}) + 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)) } @@ -2891,7 +2891,7 @@ func (w *ServerInterfaceWrapper) EnumParams(ctx echo.Context) error { var params EnumParamsParams // ------------- Optional query parameter "enumPathParam" ------------- - err = runtime.BindQueryParameter("form", true, false, "enumPathParam", ctx.QueryParams(), ¶ms.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)) } @@ -2917,7 +2917,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -2932,7 +2932,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -2947,7 +2947,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -2962,7 +2962,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -2977,7 +2977,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -2992,7 +2992,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -3022,7 +3022,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error { 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}) + 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)) } @@ -3041,7 +3041,7 @@ func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3057,7 +3057,7 @@ func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx echo.Context) 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}) + 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)) } @@ -3073,7 +3073,7 @@ func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3089,7 +3089,7 @@ func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx echo.Context) 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}) + 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)) } @@ -3105,7 +3105,7 @@ func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3121,7 +3121,7 @@ func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx echo.Context) 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}) + 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)) } @@ -3137,7 +3137,7 @@ func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3153,7 +3153,7 @@ func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx echo.Context) erro // ------------- Path parameter "id" ------------- var id Object - err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + 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)) } @@ -3184,7 +3184,7 @@ func (w *ServerInterfaceWrapper) GetDeepObject(ctx echo.Context) error { var params GetDeepObjectParams // ------------- Required query parameter "deepObj" ------------- - err = runtime.BindQueryParameter("deepObject", true, true, "deepObj", ctx.QueryParams(), ¶ms.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)) } @@ -3202,49 +3202,49 @@ func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error { var params GetQueryFormParams // ------------- Optional query parameter "ea" ------------- - err = runtime.BindQueryParameter("form", true, false, "ea", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", false, false, "a", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", true, false, "eo", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", false, false, "o", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", true, false, "ep", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", false, false, "p", ctx.QueryParams(), ¶ms.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.BindQueryParameter("form", true, false, "ps", ctx.QueryParams(), ¶ms.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)) } @@ -3264,7 +3264,7 @@ func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error { // ------------- Optional query parameter "1s" ------------- - err = runtime.BindQueryParameter("form", true, false, "1s", ctx.QueryParams(), ¶ms.N1s) + 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)) } @@ -3280,7 +3280,7 @@ func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3296,7 +3296,7 @@ func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx echo.Context) 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}) + 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)) } @@ -3312,7 +3312,7 @@ func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx echo.Context) 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}) + 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)) } @@ -3328,7 +3328,7 @@ func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx echo.Context) erro // ------------- Path parameter "param" ------------- var param Object - 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: "", Format: ""}) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err)) } @@ -3344,7 +3344,7 @@ func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) 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}) + 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)) } diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index f1afb25b19..9c0871cb34 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -504,7 +504,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 } @@ -538,7 +538,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 } @@ -599,7 +599,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 } @@ -660,7 +660,7 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s if params != nil { queryValues := queryURL.Query() - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); 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 if parsed, err := url.ParseQuery(queryFrag); err != nil { return nil, err @@ -1464,7 +1464,7 @@ 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)) } @@ -1482,7 +1482,7 @@ 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)) } @@ -1511,7 +1511,7 @@ 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)) } @@ -1533,7 +1533,7 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { 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)) } diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go index b2468c75b4..67e89ff318 100644 --- a/internal/test/server/server.gen.go +++ b/internal/test/server/server.gen.go @@ -286,7 +286,7 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re // ------------- 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}) return @@ -301,7 +301,7 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re 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}) return @@ -318,7 +318,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 @@ -347,7 +347,7 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h // ------------- 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 @@ -356,7 +356,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 @@ -381,7 +381,7 @@ func (siw *ServerInterfaceWrapper) GetWithContentType(w http.ResponseWriter, r * // ------------- 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 @@ -420,7 +420,7 @@ func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http // ------------- 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 @@ -445,7 +445,7 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt // ------------- 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 @@ -456,7 +456,7 @@ 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}) return @@ -481,7 +481,7 @@ func (siw *ServerInterfaceWrapper) UpdateResource3(w http.ResponseWriter, r *htt // ------------- 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 443fb094bf..a7c569b2c5 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -246,7 +246,7 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWr // ------------- 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 @@ -352,7 +352,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 @@ -375,7 +375,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 diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index fcdef6c6d9..b189ff5adf 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -757,7 +757,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 } @@ -1000,7 +1000,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 } @@ -1010,7 +1010,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 } diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 78eccb1770..e8e335c74a 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -136,7 +136,7 @@ func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) e // ------------- 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)) } @@ -207,7 +207,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)) } @@ -224,7 +224,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)) } diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index f33ca45430..44d3c65de7 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -121,7 +121,7 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) 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{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()) } @@ -177,7 +177,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error { 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", 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 fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error()) } @@ -197,7 +197,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error { 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", 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 fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error()) } diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 5a5b9c7582..b664de93d3 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -166,7 +166,7 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *gin.Context) { // ------------- 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{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 @@ -266,7 +266,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 @@ -288,7 +288,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 diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 0650806552..a141223fc5 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -172,7 +172,7 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWr // ------------- 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{Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err}) return @@ -278,7 +278,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 @@ -301,7 +301,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 diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index b592b21a9f..033e1dd769 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -128,7 +128,7 @@ func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx iris.Context) { // ------------- 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) @@ -193,7 +193,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) @@ -216,7 +216,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) diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index cff46fe6d7..2d6b8642ee 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -173,7 +173,7 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWr // ------------- 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 @@ -279,7 +279,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 @@ -302,7 +302,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 diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 62ec2e085e..c5ea78d298 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -131,6 +131,26 @@ 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 "" +} + func (pd ParameterDefinition) GoVariableName() string { name := LowercaseFirstCharacters(pd.GoName()) if IsGoKeyword(name) { diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index 97866fca6a..c3e7cf82ae 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -29,7 +29,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 @@ -77,7 +77,7 @@ 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}) return @@ -110,7 +110,7 @@ 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 @@ -159,7 +159,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- 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{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index d219432e29..27085038dc 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -172,7 +172,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 } @@ -210,7 +210,7 @@ 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 and .RequiresNilCheck .HasOptionalPointer}}*{{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 @@ -250,7 +250,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}}) {{end}} {{if .IsStyled}} - headerParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if .HasOptionalPointer}}*{{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 } @@ -278,7 +278,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}})) {{end}} {{if .IsStyled}} - cookieParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if .HasOptionalPointer}}*{{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 } diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index ea7b75eaad..584a21f26c 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -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)) } @@ -37,7 +37,7 @@ 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)) } @@ -79,7 +79,7 @@ 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)) } @@ -111,7 +111,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { {{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)) } diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 3213e22a7d..63bc2cb831 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -27,7 +27,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) 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{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()) } @@ -78,7 +78,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()) } @@ -108,7 +108,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) 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 fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error()) } @@ -151,7 +151,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{- 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{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()) } diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 3bc02e5d7f..272e2ec609 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -30,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { } {{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{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 @@ -75,7 +75,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 @@ -108,7 +108,7 @@ 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 @@ -155,7 +155,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { {{- 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{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 diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index e8aa9799f0..6a1b18ce2d 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -29,7 +29,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{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return @@ -77,7 +77,7 @@ 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}) return @@ -110,7 +110,7 @@ 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 @@ -159,7 +159,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- 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{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index 814e6bc4e4..0bc6b1229b 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -25,7 +25,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) @@ -46,7 +46,7 @@ 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) @@ -98,7 +98,7 @@ 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) @@ -138,7 +138,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{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 { ctx.StatusCode(http.StatusBadRequest) ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err) diff --git a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl index 09977358c8..fbccc40a03 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -29,7 +29,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ } {{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("{{.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 @@ -77,7 +77,7 @@ 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}) return @@ -110,7 +110,7 @@ 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 @@ -159,7 +159,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- 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{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err}) return From d04991e919938e6bfb5c4b018cece1d8be7b179d Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 27 Feb 2026 01:41:38 -0800 Subject: [PATCH 199/293] fix: qualify external ref schema types in default response codes (#2241) When a response uses a $ref to an external components/responses definition, the generated strict-server code for non-fixed status codes (e.g. default) used the inner schema type without the external package qualifier, causing a compile error. Apply ensureExternalRefsInSchema to response content schemas after resolving external response refs. Closes #2113 Co-authored-by: Claude Opus 4.6 --- .../test/issues/issue-2113/common/spec.yaml | 22 ++ .../test/issues/issue-2113/config.api.yaml | 11 + .../test/issues/issue-2113/config.common.yaml | 7 + internal/test/issues/issue-2113/doc.go | 4 + .../test/issues/issue-2113/gen/api/api.gen.go | 271 ++++++++++++++++++ .../issue-2113/gen/common/common.gen.go | 13 + internal/test/issues/issue-2113/issue_test.go | 22 ++ internal/test/issues/issue-2113/spec.yaml | 21 ++ pkg/codegen/operations.go | 6 + 9 files changed, 377 insertions(+) create mode 100644 internal/test/issues/issue-2113/common/spec.yaml create mode 100644 internal/test/issues/issue-2113/config.api.yaml create mode 100644 internal/test/issues/issue-2113/config.common.yaml create mode 100644 internal/test/issues/issue-2113/doc.go create mode 100644 internal/test/issues/issue-2113/gen/api/api.gen.go create mode 100644 internal/test/issues/issue-2113/gen/common/common.gen.go create mode 100644 internal/test/issues/issue-2113/issue_test.go create mode 100644 internal/test/issues/issue-2113/spec.yaml 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..f9803ed307 --- /dev/null +++ b/internal/test/issues/issue-2113/config.common.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=../../../../configuration-schema.json +package: common +generate: + models: 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..6562a7f30d --- /dev/null +++ b/internal/test/issues/issue-2113/gen/api/api.gen.go @@ -0,0 +1,271 @@ +// 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 ( + "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" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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 { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type ListThings400JSONResponse struct{ externalRef0.StandardError } + +func (response ListThings400JSONResponse) VisitListThingsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(400) + + return json.NewEncoder(w).Encode(response) +} + +type ListThingsdefaultJSONResponse struct { + Body externalRef0.ProblemDetails + StatusCode int +} + +func (response ListThingsdefaultJSONResponse) VisitListThingsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + + return json.NewEncoder(w).Encode(response.Body) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + + // (GET /things) + ListThings(ctx context.Context, request ListThingsRequestObject) (ListThingsResponseObject, error) +} + +type StrictHandlerFunc = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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..8d16de5f8f --- /dev/null +++ b/internal/test/issues/issue-2113/gen/common/common.gen.go @@ -0,0 +1,13 @@ +// 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 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/pkg/codegen/operations.go b/pkg/codegen/operations.go index c5ea78d298..eb6e3e1fd3 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -914,6 +914,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) } From efb2df3da288461287f23e49716e72025e655bcc Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Fri, 27 Feb 2026 08:50:34 +0000 Subject: [PATCH 200/293] docs: add example of using Renovate to sync files between repos --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 40c1853278..321cc42679 100644 --- a/README.md +++ b/README.md @@ -3444,6 +3444,8 @@ 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 > +> 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: From 3a5f803e489c96de22c2b9155b8298b85e667ec8 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 2 Mar 2026 06:15:39 -0800 Subject: [PATCH 201/293] feat: multi-pass type name resolution (#2213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: multi-pass type name resolution I've been meaning to use this approach for a long time, because the attempts at avoiding type collisions via structure suffixes or prefixes work sporadically, at best. Conflict resolution is fundamentally a global problem, not a local problem when doing recursive traversal, so this PR splits the code generation into two parts. First, the OAPI document structure is traversed, and all the schemas that we generate are gathered up into a list of candidates, then we do global conflict resolution across the space of all schemas. This allows us to preserve the functionality of things affected by schema name - `$ref`, `required` properties, and so forth. This fixes issue #1474 (client response wrapper type colliding with a component schema of the same name and improves issue #200 handling (same name across schemas, parameters, responses, requestBodies, headers). The new system is gated behind the existing `resolve-type-name-collisions` output option. When disabled, behavior is unchanged, oapi-codegen exits with an error. This flag is default false, so there is no behavior change to oapi-codegen unless it's specified. All current test files regenerate without any differences. Added a comprehensive test which reproduces the scenarios in all the PR's and Issues below, and adds a few more, to make sure that references to renamed targets are also correct.. Key changes: - gather.go: walks entire spec collecting schemas with location metadata - resolve_names.go: assigns unique names via context suffix, per-schema disambiguation, and numeric fallback strategies - Component schemas are privileged and keep bare names on collision - Client response wrapper types now participate in collision detection - Removed ComponentType/DefinedComp from Schema struct - Removed FixDuplicateTypeNames and related functions from utils.go Obsoletes issues: - #1474 Schema name vs client wrapper (CreateChatCompletionResponse) - #1713 Schema name vs client wrapper (CreateBlueprintResponse) - #1450 Schema name vs client wrapper (DeleteBusinessResponse) - #2097 Path response type vs schema definition (Status) - #255 Endpoint path vs response type (QueryResponse) - #899 Duplicate types from response wrapper vs schema (AccessListResponse) - #1357 Schema vs operationId response (ListAssistantsResponse, OpenAI spec) - #254 Cross-section: requestBodies vs schemas (Pet) - #407 Cross-section: requestBodies vs schemas (myThing) - #1881 Cross-section: requestBodies with multiple content types Obsoletes PRs: - #292 Parameter structures params postfix (superseded by context suffix) - #1005 Fix generate equals structs (superseded by multi-pass resolution) Co-Authored-By: Claude Opus 4.6 EOF ) * Fix linter issues * fix: apply collision strategies in global phases to prevent oscillation When multiple content types map to the same short suffix (e.g., application/json, application/merge-patch+json, and application/json-patch+json all mapping to "JSON"), the per-group strategy cascade caused an infinite oscillation: context suffix appended "RequestBody", then content type suffix appended "JSON", then context suffix fired again because the name no longer ended in "RequestBody", ad infinitum. Fix by restructuring resolveCollisions to apply each strategy as a global phase: exhaust one strategy across ALL colliding groups (re-checking for new collisions after each pass) before advancing to the next strategy. This ensures numeric fallback is reached when earlier strategies cannot disambiguate. Also fix resolvedNameForComponent to accept an optional content type for exact matching, so each media type variant of a requestBody or response gets its own resolved name instead of all variants receiving whichever name the map iterator returns first. Adds Pattern H test case (TMF622 scenario from PR #2213): a component that exists in both schemas and requestBodies where the requestBody has 3 content types that all collapse to the "JSON" short name. Co-Authored-By: Claude Opus 4.6 * Regenerate files with new code * test: add Pattern I for inline response with x-go-type $ref properties Add test case from oapi-codegen-exp#14: an inline response object whose properties $ref component schemas with x-go-type: string. In the experimental rewrite (libopenapi), this caused duplicate type declarations because libopenapi copies extensions from $ref targets. V2 (kin-openapi) handles this correctly, but the test guards against future regressions. Co-Authored-By: Claude Opus 4.6 * fix: resolve type name mismatches for multi-content-type responses When a component response has multiple JSON content types (e.g., application/json, application/json-patch+json, application/merge-patch+json), three bugs produced uncompilable code: 1. Duplicate inline type declarations: GenerateGoSchema was called with a path of [operationId, responseName] (or [responseName] in the component phase), which doesn't include the content type. When multiple content types share oneOf schemas with inline elements, they produce identically-named AdditionalTypes. If the schemas differ, the result is conflicting declarations; if they're the same, duplicate declarations. Fix: include a mediaTypeToCamelCase(contentType) segment in the schema path when jsonCount > 1, giving each content type's inline types unique names. This is guarded by jsonCount > 1 for backward compatibility. 2. Undefined types in unmarshal code: GetResponseTypeDefinitions used RefPathToGoType to resolve $ref paths like #/components/responses/200Resource_Patch, but without content type context. resolvedNameForComponent fell into a non-deterministic prefix match, returning an arbitrary per-content-type base name that didn't match any defined type when mediaTypeToCamelCase was appended. Fix: add resolvedNameForRefPath helper that parses the $ref path and delegates to resolvedNameForComponent with the specific content type for exact matching. 3. Mismatched types in response struct fields: same root cause as bug 2 — the struct field types were derived from the same non-deterministic resolution path. Additionally, promote AdditionalTypes from GenerateTypesForResponses and GenerateTypesForRequestBodies to the top-level type list, matching the existing pattern in GenerateTypesForSchemas. Without this, inline types (e.g., oneOf union members, nested objects with additionalProperties) defined inside response/requestBody schemas were silently dropped from the output. Co-Authored-By: Claude Opus 4.6 * Address greptile's comment * fix: propagate user name overrides through codegen The collision resolver had two bugs when resolve-type-name-collisions was enabled: 1. x-go-name was ignored: generateCandidateName() never consulted the x-go-name extension, so schemas/responses/requestBodies/parameters/ headers with explicit Go name overrides would lose them during collision resolution. 2. Client wrapper names bypassed the name normalizer: generateCandidateName() used UppercaseFirstCharacter(operationID) instead of SchemaNameToTypeName(operationID), so configured normalizers (e.g. ToCamelCaseWithInitialisms) were not applied to client response wrapper type names. Changes: - Add GoNameOverride field to GatheredSchema, populated from x-go-name on the parent container (schema, response, requestBody, parameter, header) when the component is not a $ref - Add extractGoNameOverride() helper to read x-go-name from extensions - Add Pinned field to ResolvedName; pinned names are returned as-is from generateCandidateName() and skipped by all collision resolution strategies (context suffix, content type, status code, param index, numeric fallback) - Fix client wrapper candidate name to use SchemaNameToTypeName() - Add unit tests for GoNameOverride population and pinning behaviour - Add integration test patterns K/L/M (x-go-name on schema, response, and requestBody) and regenerate Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- configuration-schema.json | 2 +- internal/test/issues/issue-200/config.yaml | 7 - .../test/issues/issue-200/issue200.gen.go | 295 -- .../test/issues/issue-200/issue200_test.go | 63 - internal/test/issues/issue-200/spec.yaml | 96 - .../test/name_conflict_resolution/config.yaml | 8 + .../doc.go | 2 +- .../name_conflict_resolution.gen.go | 3000 +++++++++++++++++ .../name_conflict_resolution_test.go | 460 +++ .../test/name_conflict_resolution/spec.yaml | 607 ++++ pkg/codegen/codegen.go | 131 +- pkg/codegen/configuration.go | 6 +- pkg/codegen/extension.go | 10 +- pkg/codegen/gather.go | 331 ++ pkg/codegen/gather_test.go | 356 ++ pkg/codegen/operations.go | 30 +- pkg/codegen/resolve_names.go | 339 ++ pkg/codegen/resolve_names_test.go | 379 +++ pkg/codegen/schema.go | 24 +- pkg/codegen/template_helpers.go | 7 +- pkg/codegen/utils.go | 97 +- 21 files changed, 5664 insertions(+), 586 deletions(-) delete mode 100644 internal/test/issues/issue-200/config.yaml delete mode 100644 internal/test/issues/issue-200/issue200.gen.go delete mode 100644 internal/test/issues/issue-200/issue200_test.go delete mode 100644 internal/test/issues/issue-200/spec.yaml create mode 100644 internal/test/name_conflict_resolution/config.yaml rename internal/test/{issues/issue-200 => name_conflict_resolution}/doc.go (78%) create mode 100644 internal/test/name_conflict_resolution/name_conflict_resolution.gen.go create mode 100644 internal/test/name_conflict_resolution/name_conflict_resolution_test.go create mode 100644 internal/test/name_conflict_resolution/spec.yaml create mode 100644 pkg/codegen/gather.go create mode 100644 pkg/codegen/gather_test.go create mode 100644 pkg/codegen/resolve_names.go create mode 100644 pkg/codegen/resolve_names_test.go diff --git a/configuration-schema.json b/configuration-schema.json index 43694f9658..a81feefa3c 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -255,7 +255,7 @@ }, "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 (e.g., 'Parameter', 'Response', 'RequestBody'). Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.", + "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": { diff --git a/internal/test/issues/issue-200/config.yaml b/internal/test/issues/issue-200/config.yaml deleted file mode 100644 index d68804c987..0000000000 --- a/internal/test/issues/issue-200/config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# yaml-language-server: $schema=../../../../configuration-schema.json -package: issue200 -generate: - models: true -output: issue200.gen.go -output-options: - resolve-type-name-collisions: true diff --git a/internal/test/issues/issue-200/issue200.gen.go b/internal/test/issues/issue-200/issue200.gen.go deleted file mode 100644 index 530c042c7a..0000000000 --- a/internal/test/issues/issue-200/issue200.gen.go +++ /dev/null @@ -1,295 +0,0 @@ -// Package issue200 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 issue200 - -import ( - "encoding/json" - "fmt" -) - -// 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"` -} - -// BarParam defines model for BarParam. -type BarParam = []int - -// BarParam2 defines model for BarParam2. -type BarParam2 = []int - -// BarParameter defines model for Bar. -type BarParameter = string - -// BarResponse defines model for Bar. -type BarResponse struct { - Pagination *Bar_Pagination `json:"pagination,omitempty"` - Value1 *Bar `json:"value1,omitempty"` - Value2 *Bar2 `json:"value2,omitempty"` - Value3 *BarParam `json:"value3,omitempty"` - Value4 *BarParam2 `json:"value4,omitempty"` -} - -// Bar_Pagination defines model for Bar.Pagination. -type Bar_Pagination struct { - Page *int `json:"page,omitempty"` - TotalPages *int `json:"totalPages,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// BarRequestBody defines model for Bar. -type BarRequestBody struct { - Metadata *Bar_Metadata `json:"metadata,omitempty"` - Value *int `json:"value,omitempty"` -} - -// Bar_Metadata defines model for Bar.Metadata. -type Bar_Metadata struct { - Key *string `json:"key,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// PostFooJSONBody defines parameters for PostFoo. -type PostFooJSONBody struct { - Metadata *PostFooJSONBody_Metadata `json:"metadata,omitempty"` - Value *int `json:"value,omitempty"` -} - -// PostFooParams defines parameters for PostFoo. -type PostFooParams struct { - Bar *Bar `form:"Bar,omitempty" json:"Bar,omitempty"` -} - -// PostFooJSONBody_Metadata defines parameters for PostFoo. -type PostFooJSONBody_Metadata struct { - Key *string `json:"key,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. -type PostFooJSONRequestBody PostFooJSONBody - -// Getter for additional properties for PostFooJSONBody_Metadata. Returns the specified -// element and whether it was found -func (a PostFooJSONBody_Metadata) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for PostFooJSONBody_Metadata -func (a *PostFooJSONBody_Metadata) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for PostFooJSONBody_Metadata to handle AdditionalProperties -func (a *PostFooJSONBody_Metadata) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["key"]; found { - err = json.Unmarshal(raw, &a.Key) - if err != nil { - return fmt.Errorf("error reading 'key': %w", err) - } - delete(object, "key") - } - - 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 PostFooJSONBody_Metadata to handle AdditionalProperties -func (a PostFooJSONBody_Metadata) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Key != nil { - object["key"], err = json.Marshal(a.Key) - if err != nil { - return nil, fmt.Errorf("error marshaling 'key': %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 Bar_Pagination. Returns the specified -// element and whether it was found -func (a Bar_Pagination) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for Bar_Pagination -func (a *Bar_Pagination) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for Bar_Pagination to handle AdditionalProperties -func (a *Bar_Pagination) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["page"]; found { - err = json.Unmarshal(raw, &a.Page) - if err != nil { - return fmt.Errorf("error reading 'page': %w", err) - } - delete(object, "page") - } - - if raw, found := object["totalPages"]; found { - err = json.Unmarshal(raw, &a.TotalPages) - if err != nil { - return fmt.Errorf("error reading 'totalPages': %w", err) - } - delete(object, "totalPages") - } - - 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 Bar_Pagination to handle AdditionalProperties -func (a Bar_Pagination) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Page != nil { - object["page"], err = json.Marshal(a.Page) - if err != nil { - return nil, fmt.Errorf("error marshaling 'page': %w", err) - } - } - - if a.TotalPages != nil { - object["totalPages"], err = json.Marshal(a.TotalPages) - if err != nil { - return nil, fmt.Errorf("error marshaling 'totalPages': %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 Bar_Metadata. Returns the specified -// element and whether it was found -func (a Bar_Metadata) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for Bar_Metadata -func (a *Bar_Metadata) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for Bar_Metadata to handle AdditionalProperties -func (a *Bar_Metadata) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["key"]; found { - err = json.Unmarshal(raw, &a.Key) - if err != nil { - return fmt.Errorf("error reading 'key': %w", err) - } - delete(object, "key") - } - - 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 Bar_Metadata to handle AdditionalProperties -func (a Bar_Metadata) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Key != nil { - object["key"], err = json.Marshal(a.Key) - if err != nil { - return nil, fmt.Errorf("error marshaling 'key': %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-200/issue200_test.go b/internal/test/issues/issue-200/issue200_test.go deleted file mode 100644 index 96fdb62e8b..0000000000 --- a/internal/test/issues/issue-200/issue200_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package issue200 - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// TestDuplicateTypeNamesCompile verifies that when the same name "Bar" is used -// across components/schemas, components/parameters, components/responses, -// components/requestBodies, and components/headers, the codegen produces -// distinct, compilable types with component-based suffixes. -// -// If the auto-rename logic breaks, this test will fail to compile. -func TestDuplicateTypeNamesCompile(t *testing.T) { - // Schema type: Bar (no suffix, first definition wins) - _ = Bar{Value: ptr("hello")} - - // Schema types with unique names (no collision) - _ = Bar2{Value: ptr(float32(1.0))} - _ = BarParam([]int{1, 2, 3}) - _ = BarParam2([]int{4, 5, 6}) - - // Parameter type: BarParameter (was "Bar" in components/parameters) - _ = BarParameter("query-value") - - // Response type: BarResponse (was "Bar" in components/responses) - _ = BarResponse{ - Value1: &Bar{Value: ptr("v1")}, - Value2: &Bar2{Value: ptr(float32(2.0))}, - Value3: &BarParam{1}, - Value4: &BarParam2{2}, - } - - // RequestBody type: BarRequestBody (was "Bar" in components/requestBodies) - _ = BarRequestBody{Value: ptr(42)} - - // Inline nested object with additionalProperties inside a response - // must produce a named AdditionalType (not get silently dropped). - _ = Bar_Pagination{ - Page: ptr(1), - TotalPages: ptr(10), - AdditionalProperties: map[string]string{"cursor": "abc"}, - } - - // Inline nested object with additionalProperties inside a requestBody - // must produce a named AdditionalType (not get silently dropped). - _ = Bar_Metadata{ - Key: ptr("k"), - AdditionalProperties: map[string]string{"extra": "val"}, - } - - // Operation-derived types - _ = PostFooParams{Bar: &Bar{}} - _ = PostFooJSONBody{Value: ptr(99)} - _ = PostFooJSONRequestBody{Value: ptr(100)} - - assert.True(t, true, "all duplicate-named types resolved and compiled") -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/internal/test/issues/issue-200/spec.yaml b/internal/test/issues/issue-200/spec.yaml deleted file mode 100644 index 2a68f71694..0000000000 --- a/internal/test/issues/issue-200/spec.yaml +++ /dev/null @@ -1,96 +0,0 @@ -openapi: 3.0.1 - -info: - title: "Duplicate type names test" - version: 0.0.0 - -paths: - /foo: - post: - operationId: postFoo - parameters: - - $ref: '#/components/parameters/Bar' - requestBody: - $ref: '#/components/requestBodies/Bar' - responses: - 200: - $ref: '#/components/responses/Bar' - -components: - schemas: - Bar: - type: object - properties: - value: - type: string - Bar2: - type: object - properties: - value: - type: number - BarParam: - type: array - items: - type: integer - BarParam2: - type: array - items: - type: integer - - headers: - Bar: - schema: - type: boolean - - parameters: - Bar: - name: Bar - in: query - schema: - type: string - - requestBodies: - Bar: - content: - application/json: - schema: - type: object - properties: - value: - type: integer - metadata: - type: object - properties: - key: - type: string - additionalProperties: - type: string - - 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' - value3: - $ref: '#/components/schemas/BarParam' - value4: - $ref: '#/components/schemas/BarParam2' - pagination: - type: object - properties: - page: - type: integer - totalPages: - type: integer - additionalProperties: - type: string 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/issues/issue-200/doc.go b/internal/test/name_conflict_resolution/doc.go similarity index 78% rename from internal/test/issues/issue-200/doc.go rename to internal/test/name_conflict_resolution/doc.go index 733ebfce17..4d577571ef 100644 --- a/internal/test/issues/issue-200/doc.go +++ b/internal/test/name_conflict_resolution/doc.go @@ -1,3 +1,3 @@ -package issue200 +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..068f8e6d4a --- /dev/null +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -0,0 +1,3000 @@ +// 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"` +} + +// 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("GET", 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 := queryURL.Query() + + 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 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) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("POST", 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("GET", 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("POST", 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("POST", 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("GET", 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("POST", 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("POST", 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("POST", 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("POST", 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("GET", 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("POST", 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("GET", 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("POST", 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("PATCH", 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("GET", 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("GET", 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("POST", 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"` + } +} + +// 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 +} + +type PostFooResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *BarResponse +} + +// 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 +} + +type ListItemsResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *ListItemsResponse +} + +// 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 +} + +type CreateItemResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *CreateItemResponse +} + +// 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 +} + +type CreateOrderResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Order +} + +// 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 +} + +type GetOutcomeResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *OutcomeResult +} + +// 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 +} + +type PostOutcomeResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type SendPayloadResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Payload +} + +// 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 +} + +type CreatePetResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Pet +} + +// 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 +} + +type QueryResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *QueryResponse +} + +// 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 +} + +type GetQuxResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *QuxResponse +} + +// 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 +} + +type PostQuxResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetRenamedSchemaResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Renamer +} + +// 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 +} + +type PostRenamedSchemaResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type PatchResourceResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *N200ResourcePatchResponseJSONApplicationJSON + ApplicationjsonPatchJSON200 *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON + ApplicationjsonPatchQueryJSON200 *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON + ApplicationmergePatchJSON200 *N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON +} +type PatchResource200ApplicationJSONPatchPlusJSON1 = []Resource +type PatchResource200ApplicationJSONPatchPlusJSON2 = string +type PatchResource200ApplicationJSONPatchQueryPlusJSON1 = []Resource +type PatchResource200ApplicationJSONPatchQueryPlusJSON2 = string + +// 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 +} + +type GetStatusResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *GetStatusResponse +} + +// 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 +} + +type GetZapResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *ZapResponse +} + +// 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 +} + +type PostZapResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +// 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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 0f38b6ff7f..281574a68f 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -54,6 +54,12 @@ var globalState struct { 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 } // goImport represents a go package to be imported in the generated code @@ -176,6 +182,28 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { globalState.initialismsMap = makeInitialismsMap(opts.OutputOptions.AdditionalInitialisms) + // 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) @@ -614,6 +642,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, @@ -642,6 +674,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, @@ -689,7 +725,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) } @@ -699,7 +750,9 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response return nil, fmt.Errorf("error making name for components/responses/%s: %w", responseName, err) } - goType.DefinedComp = ComponentTypeResponse + if resolved := resolvedNameForComponent("responses", responseName, mediaType); resolved != "" { + goTypeName = resolved + } typeDef := TypeDefinition{ JsonName: responseName, @@ -738,7 +791,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 } @@ -753,7 +807,9 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open return nil, fmt.Errorf("error making name for components/schemas/%s: %w", requestBodyName, err) } - goType.DefinedComp = ComponentTypeRequestBody + if resolved := resolvedNameForComponent("requestBodies", requestBodyName, mediaType); resolved != "" { + goTypeName = resolved + } typeDef := TypeDefinition{ JsonName: requestBodyName, @@ -782,15 +838,11 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) m := map[string]TypeDefinition{} var ts []TypeDefinition - if globalState.options.OutputOptions.ResolveTypeNameCollisions { - types = FixDuplicateTypeNames(types) - } - for _, typ := range types { if prevType, found := m[typ.TypeName]; found { - // If type names collide after auto-rename, 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. + // 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. if TypeDefinitionsEquivalent(prevType, typ) { continue } @@ -812,6 +864,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 { + sort.Strings(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{} diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 4598bb04ad..6f4df06a0f 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -305,8 +305,10 @@ type OutputOptions struct { // 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"). Without this, the codegen will error on duplicate type - // names, requiring manual resolution via x-go-name. + // "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. diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index 6bc6bff144..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,7 +17,10 @@ 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" diff --git a/pkg/codegen/gather.go b/pkg/codegen/gather.go new file mode 100644 index 0000000000..84bd7e55df --- /dev/null +++ b/pkg/codegen/gather.go @@ -0,0 +1,331 @@ +package codegen + +import ( + "fmt" + "sort" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/oapi-codegen/oapi-codegen/v2/pkg/util" +) + +// 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, "/") +} + +// 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 = append(schemas, gatherComponentSchemas(spec.Components)...) + schemas = append(schemas, gatherComponentParameters(spec.Components)...) + schemas = append(schemas, gatherComponentResponses(spec.Components)...) + schemas = append(schemas, gatherComponentRequestBodies(spec.Components)...) + schemas = append(schemas, 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 { + var result []*GatheredSchema + + if spec.Paths == nil { + return result + } + + // 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 + sort.Slice(ops, func(i, j int) bool { + return ops[i].op.OperationID < ops[j].op.OperationID + }) + + 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/operations.go b/pkg/codegen/operations.go index eb6e3e1fd3..3c639d22dc 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -342,7 +342,29 @@ 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{o.OperationId, responseName}) + // When a response has multiple JSON content types (e.g., + // application/json, application/json-patch+json, and + // application/merge-patch+json), we include a content-type-derived + // segment in the schema path. This is necessary because + // GenerateGoSchema uses the path to name any inline types it + // creates (e.g., oneOf union members). Without the content type + // in the path, all content types for the same response produce + // identically-named inline types. If those content types have + // different schemas, the result is conflicting type declarations; + // if they have the same schema, the result is duplicate + // declarations. Both cases produce code that won't compile. + // + // 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{o.OperationId, responseName} + if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) && globalState.options.OutputOptions.ResolveTypeNameCollisions { + schemaPath = append(schemaPath, mediaTypeToCamelCase(contentTypeName)) + } + 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) } @@ -386,7 +408,11 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini return nil, fmt.Errorf("error dereferencing response Ref: %w", err) } if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) { - refType += mediaTypeToCamelCase(contentTypeName) + if resolved := resolvedNameForRefPath(responseRef.Ref, contentTypeName); resolved != "" { + refType = resolved + mediaTypeToCamelCase(contentTypeName) + } else { + refType += mediaTypeToCamelCase(contentTypeName) + } } td.Schema.RefType = refType } diff --git a/pkg/codegen/resolve_names.go b/pkg/codegen/resolve_names.go new file mode 100644 index 0000000000..f6d65f5b92 --- /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 iter := 0; iter < maxIterations; iter++ { + 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 := 0; i < len(group); i++ { + 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 067d03955d..ff72d23b6b 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -40,21 +40,8 @@ type Schema struct { // The original OpenAPIv3 Schema. OAPISchema *openapi3.Schema - DefinedComp ComponentType // Indicates which component section defined this type } -// ComponentType is used to keep track of where a given schema came from, in order -// to perform type name collision resolution. -type ComponentType int - -const ( - ComponentTypeSchema = iota - ComponentTypeParameter - ComponentTypeRequestBody - ComponentTypeResponse - ComponentTypeHeader -) - func (s Schema) IsRef() bool { return s.RefType != "" } @@ -325,7 +312,6 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { Description: schema.Description, OAPISchema: schema, SkipOptionalPointer: skipOptionalPointer, - DefinedComp: ComponentTypeSchema, } // AllOf is interesting, and useful. It's the union of a number of other @@ -835,9 +821,7 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { // We can process the schema through the generic schema processor if param.Schema != nil { - schema, err := GenerateGoSchema(param.Schema, path) - schema.DefinedComp = ComponentTypeParameter - return schema, err + return GenerateGoSchema(param.Schema, path) } // At this point, we have a content type. We know how to deal with @@ -847,7 +831,6 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), - DefinedComp: ComponentTypeParameter, }, nil } @@ -858,14 +841,11 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), - DefinedComp: ComponentTypeParameter, }, nil } // For json, we go through the standard schema mechanism - schema, err := GenerateGoSchema(mt.Schema, path) - schema.DefinedComp = ComponentTypeParameter - return schema, err + return GenerateGoSchema(mt.Schema, path) } func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminator *openapi3.Discriminator, path []string) error { diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 64caf12828..e4d932116a 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -259,8 +259,13 @@ func buildUnmarshalCaseStrict(typeDefinition ResponseTypeDefinition, 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) } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 549d5cffa3..adfeb7c89f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -474,6 +474,20 @@ func refPathToGoTypeSelf(refPath string, local bool) (string, error) { return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) } + // When multi-pass name resolution is active, the resolved name takes + // precedence over the spec-given name. For a $ref like + // #/components/schemas/Thing, we pass the section ("schemas") and + // name ("Thing") to resolvedNameForComponent, which looks up the + // final Go type name assigned by the collision resolver. + // Note: the resolver prioritizes component schemas — if a schema and + // a response both claim "Thing", the component schema keeps the original + // name and the response becomes "ThingResponse". + if depth == 4 && pathParts[0] == "#" && pathParts[1] == "components" { + if resolved := resolvedNameForComponent(pathParts[2], pathParts[3]); resolved != "" { + return resolved, nil + } + } + // Schemas may have been renamed locally, so look up the actual name in // the spec. name, err := findSchemaNameByRefPath(refPath, globalState.spec) @@ -1124,86 +1138,3 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool { func sliceContains[E comparable](s []E, v E) bool { return slices.Contains(s, v) } - -// FixDuplicateTypeNames renames duplicate type names. -func FixDuplicateTypeNames(typeDefs []TypeDefinition) []TypeDefinition { - if !hasDuplicatedTypeNames(typeDefs) { - return typeDefs - } - - // try to fix duplicate type names with their definition section - typeDefs = fixDuplicateTypeNamesWithCompName(typeDefs) - if !hasDuplicatedTypeNames(typeDefs) { - return typeDefs - } - - const maxIter = 100 - for i := 0; i < maxIter && hasDuplicatedTypeNames(typeDefs); i++ { - typeDefs = fixDuplicateTypeNamesDupCounts(typeDefs) - } - - if hasDuplicatedTypeNames(typeDefs) { - panic("too much duplicate type names") - } - - return typeDefs -} - -func hasDuplicatedTypeNames(typeDefs []TypeDefinition) bool { - dupCheck := make(map[string]int, len(typeDefs)) - - for _, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - return true - } - } - - return false -} - -func fixDuplicateTypeNamesWithCompName(typeDefs []TypeDefinition) []TypeDefinition { - dupCheck := make(map[string]int, len(typeDefs)) - deDup := make([]TypeDefinition, len(typeDefs)) - - for i, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - switch d.Schema.DefinedComp { - case ComponentTypeSchema: - d.TypeName += "Schema" - case ComponentTypeParameter: - d.TypeName += "Parameter" - case ComponentTypeRequestBody: - d.TypeName += "RequestBody" - case ComponentTypeResponse: - d.TypeName += "Response" - case ComponentTypeHeader: - d.TypeName += "Header" - } - } - - deDup[i] = d - } - - return deDup -} - -func fixDuplicateTypeNamesDupCounts(typeDefs []TypeDefinition) []TypeDefinition { - dupCheck := make(map[string]int, len(typeDefs)) - deDup := make([]TypeDefinition, len(typeDefs)) - - for i, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - d.TypeName = d.TypeName + strconv.Itoa(dupCheck[d.TypeName]) - } - - deDup[i] = d - } - - return deDup -} From c966b373e95f4385b33e04424b08d70757466895 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 2 Mar 2026 06:16:57 -0800 Subject: [PATCH 202/293] fix: use RequiresNilCheck for all params (#2263) PR #2237 fixed query parameters to use RequiresNilCheck instead of HasOptionalPointer for nil-check guards, but the same bug remained in the header and cookie parameter sections of client.tmpl. This caused optional array params (e.g. []string) to be sent even when nil, because prefer-skip-optional-pointer removes the pointer wrapper and HasOptionalPointer returns false, skipping the nil check entirely. Co-authored-by: Claude Opus 4.6 --- internal/test/issues/issue-2238/config.yaml | 7 + internal/test/issues/issue-2238/generate.go | 3 + .../test/issues/issue-2238/issue2238.gen.go | 262 ++++++++++++++++++ .../test/issues/issue-2238/issue2238_test.go | 56 ++++ internal/test/issues/issue-2238/openapi.yaml | 22 ++ pkg/codegen/templates/client.tmpl | 8 +- 6 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 internal/test/issues/issue-2238/config.yaml create mode 100644 internal/test/issues/issue-2238/generate.go create mode 100644 internal/test/issues/issue-2238/issue2238.gen.go create mode 100644 internal/test/issues/issue-2238/issue2238_test.go create mode 100644 internal/test/issues/issue-2238/openapi.yaml 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..81f395ddfa --- /dev/null +++ b/internal/test/issues/issue-2238/issue2238.gen.go @@ -0,0 +1,262 @@ +// 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("GET", 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 +} + +// 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 +} + +// 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/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 27085038dc..24410dfae6 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -236,7 +236,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr {{ if .HeaderParams }} if params != nil { {{range $paramIdx, $param := .HeaderParams}} - {{if .HasOptionalPointer}} if params.{{.GoName}} != nil { {{end}} + {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}} var headerParam{{$paramIdx}} string {{if .IsPassThrough}} headerParam{{$paramIdx}} = {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}} @@ -256,7 +256,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr } {{end}} req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}}) - {{if .HasOptionalPointer}}}{{end}} + {{if .RequiresNilCheck}}}{{end}} {{end}} } {{- end }}{{/* if .HeaderParams */}} @@ -264,7 +264,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr {{ if .CookieParams }} if params != nil { {{range $paramIdx, $param := .CookieParams}} - {{if .HasOptionalPointer}} if params.{{.GoName}} != nil { {{end}} + {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}} var cookieParam{{$paramIdx}} string {{if .IsPassThrough}} cookieParam{{$paramIdx}} = {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}} @@ -288,7 +288,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr Value:cookieParam{{$paramIdx}}, } req.AddCookie(cookie{{$paramIdx}}) - {{if .HasOptionalPointer}}}{{end}} + {{if .RequiresNilCheck}}}{{end}} {{ end -}} } {{- end }}{{/* if .CookieParams */}} From 863c6ea3f57ed8ec5c0826e1733aa4cb134a55d3 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 2 Mar 2026 06:18:51 -0800 Subject: [PATCH 203/293] Update all dependencies to Go 1.24 (#2264) * chore: require go 1.24 as minimum version across all modules Bump all go.mod files from go 1.22.5 to go 1.24 and normalize any go 1.24.0 to go 1.24 for consistency. Co-Authored-By: Claude Opus 4.6 * chore: remove inner go.mod files that existed only for go 1.24 requirement Now that all modules require go 1.24, these inner modules are no longer needed as separate modules. Their packages are absorbed by the parent modules (internal/test and examples), which now include the fiber dependencies directly. Removed inner modules: - internal/test/strict-server/fiber/ - internal/test/issues/issue1469/ - internal/test/issues/issue-1529/strict-fiber/ - examples/minimal-server/stdhttp-go-tool/ - examples/minimal-server/fiber/ - examples/extensions/xomitzero/ - examples/petstore-expanded/fiber/ - examples/output-options/preferskipoptionalpointerwithomitzero/ Co-Authored-By: Claude Opus 4.6 * chore: update dependencies to latest go 1.24-compatible versions Run go get for all direct dependencies across all modules, constrained to go 1.24 via GOTOOLCHAIN=go1.24.4 to avoid pulling in deps that require go 1.25. Notable updates: - gin v1.10.1 -> v1.11.0 (v1.12.0 requires go 1.25) - iris v12.2.6 -> v12.2.11 - echo v4.11.4/v4.12.0 -> v4.15.1 - chi v5.0.10 -> v5.2.5 - golang.org/x/tools v0.30.0 -> v0.42.0 - golang.org/x/mod v0.23.0 -> v0.33.0 - golang.org/x/text v0.20.0 -> v0.34.0 Pinned speakeasy-api/jsonpath at v0.6.0 across all modules due to v0.6.1+ removing the pkg/overlay package that openapi-overlay tests depend on. Pinned dprotaso/go-yit at the pre-yaml/v4 version as the newer version switches to go.yaml.in/yaml/v4 which is incompatible with vmware-labs/yaml-jsonpath. Co-Authored-By: Claude Opus 4.6 * update readme * ci: skip Go 1.22 and 1.23 in CI matrix Now that all modules require go 1.24, exclude older versions from the CI build/test/tidy/generate matrix via the excluding_versions input on the reusable workflow. Co-Authored-By: Claude Opus 4.6 * chore: remove Go version guards from child module Makefiles Now that go 1.24 is the minimum version, the execute-if-go-122/124 guards are always true. Simplify the Makefiles to run commands directly. Co-Authored-By: Claude Opus 4.6 * chore: update deprecated code Remove usage of deprecated middleware.Logger() from Echo examples and tests. This was deprecated in Echo v4.15.1 in favor of middleware.RequestLogger or middleware.RequestLoggerWithConfig. Since these calls only added request logging for debugging convenience, they are removed rather than replaced. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .github/workflows/ci.yml | 1 + README.md | 25 -- examples/authenticated-api/echo/main.go | 2 - examples/authenticated-api/stdhttp/Makefile | 31 +- examples/authenticated-api/stdhttp/go.mod | 34 +-- examples/authenticated-api/stdhttp/go.sum | 118 +++----- examples/extensions/xomitzero/Makefile | 36 --- examples/extensions/xomitzero/go.mod | 35 --- examples/extensions/xomitzero/go.sum | 173 ----------- examples/go.mod | 107 +++---- examples/go.sum | 274 +++++++++--------- examples/minimal-server/fiber/Makefile | 36 --- examples/minimal-server/fiber/go.mod | 44 --- examples/minimal-server/fiber/go.sum | 198 ------------- .../minimal-server/stdhttp-go-tool/Makefile | 36 --- .../minimal-server/stdhttp-go-tool/go.mod | 31 -- .../minimal-server/stdhttp-go-tool/go.sum | 173 ----------- examples/minimal-server/stdhttp/Makefile | 31 +- examples/minimal-server/stdhttp/go.mod | 20 +- examples/minimal-server/stdhttp/go.sum | 63 ++-- .../Makefile | 36 --- .../go.mod | 35 --- .../go.sum | 173 ----------- examples/petstore-expanded/echo/petstore.go | 3 - .../petstore-expanded/echo/petstore_test.go | 4 - examples/petstore-expanded/fiber/Makefile | 36 --- examples/petstore-expanded/fiber/go.mod | 53 ---- examples/petstore-expanded/fiber/go.sum | 212 -------------- examples/petstore-expanded/stdhttp/Makefile | 31 +- examples/petstore-expanded/stdhttp/go.mod | 28 +- examples/petstore-expanded/stdhttp/go.sum | 71 +++-- go.mod | 24 +- go.sum | 59 ++-- internal/test/go.mod | 102 ++++--- internal/test/go.sum | 242 ++++++++-------- .../issues/issue-1529/strict-fiber/Makefile | 36 --- .../issues/issue-1529/strict-fiber/go.mod | 46 --- .../issues/issue-1529/strict-fiber/go.sum | 198 ------------- .../issue-1529/strict-fiber/issue1529.gen.go | 2 +- internal/test/issues/issue1469/Makefile | 36 --- internal/test/issues/issue1469/go.mod | 49 ---- internal/test/issues/issue1469/go.sum | 198 ------------- internal/test/parameters/parameters_test.go | 4 - internal/test/strict-server/fiber/Makefile | 36 --- internal/test/strict-server/fiber/go.mod | 55 ---- internal/test/strict-server/fiber/go.sum | 210 -------------- internal/test/strict-server/stdhttp/Makefile | 31 +- internal/test/strict-server/stdhttp/go.mod | 26 +- internal/test/strict-server/stdhttp/go.sum | 71 +++-- 49 files changed, 632 insertions(+), 2943 deletions(-) delete mode 100644 examples/extensions/xomitzero/Makefile delete mode 100644 examples/extensions/xomitzero/go.mod delete mode 100644 examples/extensions/xomitzero/go.sum delete mode 100644 examples/minimal-server/fiber/Makefile delete mode 100644 examples/minimal-server/fiber/go.mod delete mode 100644 examples/minimal-server/fiber/go.sum delete mode 100644 examples/minimal-server/stdhttp-go-tool/Makefile delete mode 100644 examples/minimal-server/stdhttp-go-tool/go.mod delete mode 100644 examples/minimal-server/stdhttp-go-tool/go.sum delete mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/Makefile delete mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/go.mod delete mode 100644 examples/output-options/preferskipoptionalpointerwithomitzero/go.sum delete mode 100644 examples/petstore-expanded/fiber/Makefile delete mode 100644 examples/petstore-expanded/fiber/go.mod delete mode 100644 examples/petstore-expanded/fiber/go.sum delete mode 100644 internal/test/issues/issue-1529/strict-fiber/Makefile delete mode 100644 internal/test/issues/issue-1529/strict-fiber/go.mod delete mode 100644 internal/test/issues/issue-1529/strict-fiber/go.sum delete mode 100644 internal/test/issues/issue1469/Makefile delete mode 100644 internal/test/issues/issue1469/go.mod delete mode 100644 internal/test/issues/issue1469/go.sum delete mode 100644 internal/test/strict-server/fiber/Makefile delete mode 100644 internal/test/strict-server/fiber/go.mod delete mode 100644 internal/test/strict-server/fiber/go.sum diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a010b440e..2d5e0a1c6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ jobs: build: uses: oapi-codegen/actions/.github/workflows/ci.yml@75566d848d25021f137594c947f26171094fb511 # v0.5.0 with: + excluding_versions: '["1.22", "1.23"]' lint_versions: '["1.25"]' build-binaries: diff --git a/README.md b/README.md index 321cc42679..da058e65a5 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,6 @@ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest ## Install -### For Go 1.24+ - It is recommended to follow [the `go tool` support available from Go 1.24+](https://www.jvt.me/posts/2025/01/27/go-tools-124/) for managing the dependency of `oapi-codegen` alongside your core application. To do this, you run `go get -tool`: @@ -59,29 +57,6 @@ From there, each invocation of `oapi-codegen` would be used like so: //go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml ``` -### Prior to Go 1.24 - -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 - -package main - -import ( - _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" -) -``` - -Then, 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 -``` - Alternatively, you can install it as a binary with: ```sh 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/stdhttp/Makefile b/examples/authenticated-api/stdhttp/Makefile index 48fe768e30..5ec0edd058 100644 --- a/examples/authenticated-api/stdhttp/Makefile +++ b/examples/authenticated-api/stdhttp/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -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 ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-122,go generate ./...) + go generate ./... test: - $(call execute-if-go-122,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-122,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-122,tidied -verbose) + tidied -verbose diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 3a2081ba2a..64d200dc01 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -1,25 +1,25 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( github.com/getkin/kin-openapi v0.133.0 - github.com/lestrrat-go/jwx v1.2.29 - github.com/oapi-codegen/nethttp-middleware v1.0.2 + github.com/lestrrat-go/jwx v1.2.31 + 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/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // 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/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect @@ -27,22 +27,22 @@ require ( 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/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.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 index a6e130e447..372e7efe62 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -2,11 +2,11 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= 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= @@ -15,15 +15,17 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 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= @@ -46,13 +48,11 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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= @@ -61,20 +61,20 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ 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/jwx v1.2.31 h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54= +github.com/lestrrat-go/jwx v1.2.31/go.mod h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c= 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/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/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/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA= +github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= @@ -97,71 +97,51 @@ github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX 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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= 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.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.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/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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -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/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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.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/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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-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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -176,36 +156,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.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/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= 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.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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -219,9 +184,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/examples/extensions/xomitzero/Makefile b/examples/extensions/xomitzero/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/examples/extensions/xomitzero/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/examples/extensions/xomitzero/go.mod b/examples/extensions/xomitzero/go.mod deleted file mode 100644 index 6b1e3678b8..0000000000 --- a/examples/extensions/xomitzero/go.mod +++ /dev/null @@ -1,35 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/extensions/xomitzero - -go 1.24 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require ( - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/examples/extensions/xomitzero/go.sum b/examples/extensions/xomitzero/go.sum deleted file mode 100644 index fdce2066b1..0000000000 --- a/examples/extensions/xomitzero/go.sum +++ /dev/null @@ -1,173 +0,0 @@ -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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.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/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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/examples/go.mod b/examples/go.mod index 04cb27ccd2..0b92bb2e87 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,27 +1,29 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( github.com/getkin/kin-openapi v0.133.0 - github.com/gin-gonic/gin v1.10.1 - github.com/go-chi/chi/v5 v5.0.10 + github.com/gin-gonic/gin v1.11.0 + github.com/go-chi/chi/v5 v5.2.5 + github.com/gofiber/fiber/v2 v2.52.12 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/lestrrat-go/jwx v1.2.31 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.2.0 - github.com/oapi-codegen/testutil v1.0.0 + github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 + golang.org/x/lint v0.0.0-20241112194109-818c5a804067 ) require ( @@ -33,84 +35,91 @@ require ( github.com/andybalholm/brotli v1.1.0 // 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/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // 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.8 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // 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/go-playground/validator/v10 v10.27.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect + github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kataras/blocks v0.0.7 // indirect - github.com/kataras/golog v0.1.9 // indirect - github.com/kataras/pio v0.0.12 // indirect + github.com/kataras/blocks v0.0.8 // 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.9 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/labstack/gommon v0.4.2 // 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.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/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/mailru/easyjson v0.9.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/microcosm-cc/bluemonday v1.0.25 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/microcosm-cc/bluemonday v1.0.26 // 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.9.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/tdewolff/minify/v2 v2.12.9 // indirect - github.com/tdewolff/parse/v2 v2.6.8 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/tdewolff/minify/v2 v2.20.19 // indirect + github.com/tdewolff/parse/v2 v2.7.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.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/valyala/tcplisten v1.0.0 // 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/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect - golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.30.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.20.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.42.0 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 7a8759d76b..180de2d19d 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -20,23 +20,21 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP 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/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= 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/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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= 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.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= 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= @@ -48,39 +46,43 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= 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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= -github.com/gin-gonic/gin v1.10.1/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/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= +github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +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.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -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/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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/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= @@ -92,14 +94,14 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4= -github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= +github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/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.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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= @@ -110,8 +112,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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= @@ -125,61 +127,57 @@ 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.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= +github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= +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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs= +github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c= 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/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.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.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= -github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= +github.com/lestrrat-go/jwx v1.2.31 h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54= +github.com/lestrrat-go/jwx v1.2.31/go.mod h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c= 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/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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= 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= @@ -189,22 +187,26 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/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/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oapi-codegen/echo-middleware v1.0.2 h1:oNBqiE7jd/9bfGNk/bpbX2nqWrtPc+LL4Boya8Wl81U= github.com/oapi-codegen/echo-middleware v1.0.2/go.mod h1:5J6MFcGqrpWLXpbKGZtRPZViLIHyyyUHlkqg6dT2R4E= +github.com/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI= +github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg= github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFDAUUWaJT0k0eI= github.com/oapi-codegen/gin-middleware v1.0.2/go.mod h1:2HJDQjH8jzK2/k/VKcWl+/T41H7ai2bKa6dN3AA2GpA= github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq1eze4mamhT5hU= github.com/oapi-codegen/iris-middleware v1.0.5/go.mod h1:/ysgvbjWyhfDAouIeUOjzIv+zsXfaIXlAQrsOU9/Kyo= -github.com/oapi-codegen/nethttp-middleware v1.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/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA= +github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -221,16 +223,22 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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/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.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +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/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= @@ -244,13 +252,12 @@ github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -260,32 +267,35 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/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.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/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= +github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= +github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= +github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/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.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/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/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -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/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.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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -302,49 +312,41 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn 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.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= 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/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.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -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.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -361,38 +363,27 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w 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-20211216021012-1d35b9e2eb4e/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-20220715151400-c0bba94af5f8/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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -405,13 +396,12 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -429,5 +419,3 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/examples/minimal-server/fiber/Makefile b/examples/minimal-server/fiber/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/examples/minimal-server/fiber/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/examples/minimal-server/fiber/go.mod b/examples/minimal-server/fiber/go.mod deleted file mode 100644 index 58abd2fa35..0000000000 --- a/examples/minimal-server/fiber/go.mod +++ /dev/null @@ -1,44 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber - -go 1.24.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require github.com/gofiber/fiber/v2 v2.52.11 - -require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.9 // 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.16 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/examples/minimal-server/fiber/go.sum b/examples/minimal-server/fiber/go.sum deleted file mode 100644 index e2954b1efc..0000000000 --- a/examples/minimal-server/fiber/go.sum +++ /dev/null @@ -1,198 +0,0 @@ -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/examples/minimal-server/stdhttp-go-tool/Makefile b/examples/minimal-server/stdhttp-go-tool/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/examples/minimal-server/stdhttp-go-tool/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/examples/minimal-server/stdhttp-go-tool/go.mod b/examples/minimal-server/stdhttp-go-tool/go.mod deleted file mode 100644 index de08a03c54..0000000000 --- a/examples/minimal-server/stdhttp-go-tool/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp-go-tool - -go 1.24 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // 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/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.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-tool/go.sum b/examples/minimal-server/stdhttp-go-tool/go.sum deleted file mode 100644 index fdce2066b1..0000000000 --- a/examples/minimal-server/stdhttp-go-tool/go.sum +++ /dev/null @@ -1,173 +0,0 @@ -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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.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/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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/examples/minimal-server/stdhttp/Makefile b/examples/minimal-server/stdhttp/Makefile index 48fe768e30..5ec0edd058 100644 --- a/examples/minimal-server/stdhttp/Makefile +++ b/examples/minimal-server/stdhttp/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -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 ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-122,go generate ./...) + go generate ./... test: - $(call execute-if-go-122,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-122,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-122,tidied -verbose) + tidied -verbose diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index f1ef1ba7b4..98ad587fc4 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ @@ -9,22 +9,22 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.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 index fdce2066b1..e5ac6ef8cc 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -2,8 +2,9 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/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= @@ -12,10 +13,12 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -39,15 +42,13 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -71,16 +72,15 @@ 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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= 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= @@ -90,15 +90,15 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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= @@ -106,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -127,21 +127,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -155,9 +155,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile b/examples/output-options/preferskipoptionalpointerwithomitzero/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod b/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod deleted file mode 100644 index 6f75dac750..0000000000 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.mod +++ /dev/null @@ -1,35 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/output-options/preferskipoptionalpointerwithomitzero - -go 1.24 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require ( - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum b/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum deleted file mode 100644 index fdce2066b1..0000000000 --- a/examples/output-options/preferskipoptionalpointerwithomitzero/go.sum +++ /dev/null @@ -1,173 +0,0 @@ -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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.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/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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/examples/petstore-expanded/echo/petstore.go b/examples/petstore-expanded/echo/petstore.go index 5ea0250507..7287d2b354 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" ) @@ -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..092e6238e8 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" @@ -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/fiber/Makefile b/examples/petstore-expanded/fiber/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/examples/petstore-expanded/fiber/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/examples/petstore-expanded/fiber/go.mod b/examples/petstore-expanded/fiber/go.mod deleted file mode 100644 index 848ae29799..0000000000 --- a/examples/petstore-expanded/fiber/go.mod +++ /dev/null @@ -1,53 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/fiber - -go 1.24.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/getkin/kin-openapi v0.133.0 - github.com/gofiber/fiber/v2 v2.52.11 - github.com/oapi-codegen/fiber-middleware v1.0.2 - github.com/oapi-codegen/runtime v1.2.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.9 // 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.16 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/examples/petstore-expanded/fiber/go.sum b/examples/petstore-expanded/fiber/go.sum deleted file mode 100644 index 4d328b9424..0000000000 --- a/examples/petstore-expanded/fiber/go.sum +++ /dev/null @@ -1,212 +0,0 @@ -github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/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/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/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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI= -github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg= -github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/examples/petstore-expanded/stdhttp/Makefile b/examples/petstore-expanded/stdhttp/Makefile index 48fe768e30..5ec0edd058 100644 --- a/examples/petstore-expanded/stdhttp/Makefile +++ b/examples/petstore-expanded/stdhttp/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -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 ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-122,go generate ./...) + go generate ./... test: - $(call execute-if-go-122,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-122,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-122,tidied -verbose) + tidied -verbose diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index cd3edaec36..3922deb19e 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -1,41 +1,41 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( github.com/getkin/kin-openapi v0.133.0 - 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.2.0 - github.com/oapi-codegen/testutil v1.0.0 + github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.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.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/google/uuid v1.5.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.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 index 33f9b11fbb..677ca72245 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -6,8 +6,9 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/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= @@ -16,10 +17,12 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -48,26 +51,24 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/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/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/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA= +github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -86,16 +87,15 @@ 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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= 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= @@ -107,15 +107,15 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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= @@ -123,13 +123,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -144,21 +144,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -172,9 +172,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/go.mod b/go.mod index 12e391a6ee..ce84f98d4e 100644 --- a/go.mod +++ b/go.mod @@ -1,33 +1,35 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.22.5 +go 1.24.3 + +toolchain go1.24.4 require ( github.com/getkin/kin-openapi v0.133.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.11.1 - golang.org/x/mod v0.23.0 - golang.org/x/text v0.20.0 - golang.org/x/tools v0.30.0 + golang.org/x/mod v0.33.0 + golang.org/x/text v0.34.0 + golang.org/x/tools v0.42.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/davecgh/go-spew v1.1.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.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/sync v0.11.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/sync v0.19.0 // indirect ) diff --git a/go.sum b/go.sum index fdce2066b1..8e99a7a7fd 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,9 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/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= @@ -12,10 +13,12 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -39,15 +42,13 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -71,10 +72,9 @@ 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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= @@ -90,15 +90,15 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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= @@ -106,13 +106,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -127,21 +127,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -155,9 +155,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index f027d757f8..6f70f67ca3 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,21 +1,22 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( github.com/getkin/kin-openapi v0.133.0 - github.com/gin-gonic/gin v1.10.1 - github.com/go-chi/chi/v5 v5.0.10 - github.com/google/uuid v1.5.0 + github.com/gin-gonic/gin v1.11.0 + github.com/go-chi/chi/v5 v5.2.5 + github.com/gofiber/fiber/v2 v2.52.12 + 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.4 - 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/oapi-codegen/nullable v1.1.0 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 github.com/oapi-codegen/runtime v1.2.0 - github.com/oapi-codegen/testutil v1.0.0 + github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -26,81 +27,88 @@ require ( github.com/CloudyKit/jet/v6 v6.2.0 // indirect github.com/Joker/jade v1.1.3 // indirect github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // 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/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // 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.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.8 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // 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/go-playground/validator/v10 v10.27.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/goccy/go-yaml v1.18.0 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect + github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kataras/blocks v0.0.7 // indirect - github.com/kataras/golog v0.1.9 // indirect - github.com/kataras/pio v0.0.12 // indirect + github.com/kataras/blocks v0.0.8 // 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.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/labstack/gommon v0.4.2 // 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/mailru/easyjson v0.9.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/microcosm-cc/bluemonday v1.0.25 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/microcosm-cc/bluemonday v1.0.26 // 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.9.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // 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.20.19 // indirect + github.com/tdewolff/parse/v2 v2.7.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.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/valyala/tcplisten v1.0.0 // 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/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect - golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.30.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.20.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.42.0 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/test/go.sum b/internal/test/go.sum index 2d726a40f9..d4d3ba66ee 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -13,27 +13,26 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 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/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= 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/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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= 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/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= @@ -45,30 +44,32 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= 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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= -github.com/gin-gonic/gin v1.10.1/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/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= +github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +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.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -76,8 +77,10 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 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/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/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/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= @@ -89,26 +92,26 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4= -github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= +github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/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.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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/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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= 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.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +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= @@ -122,48 +125,44 @@ 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.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= +github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= +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.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.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= -github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +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/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= 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.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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= 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= @@ -173,16 +172,18 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/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/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/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.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -199,14 +200,19 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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/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.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= @@ -220,8 +226,8 @@ github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= 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= @@ -232,37 +238,39 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.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.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/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= +github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= +github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= +github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/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.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/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/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -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/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.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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -279,18 +287,21 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn 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.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= -golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= 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/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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= @@ -300,14 +311,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -325,27 +336,25 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -358,13 +367,12 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -382,5 +390,3 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/test/issues/issue-1529/strict-fiber/Makefile b/internal/test/issues/issue-1529/strict-fiber/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/internal/test/issues/issue-1529/strict-fiber/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/issues/issue-1529/strict-fiber/go.mod b/internal/test/issues/issue-1529/strict-fiber/go.mod deleted file mode 100644 index 5e881be269..0000000000 --- a/internal/test/issues/issue-1529/strict-fiber/go.mod +++ /dev/null @@ -1,46 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1529/strict-fiber - -go 1.24.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/getkin/kin-openapi v0.133.0 - github.com/gofiber/fiber/v2 v2.52.11 -) - -require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.9 // 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.16 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/internal/test/issues/issue-1529/strict-fiber/go.sum b/internal/test/issues/issue-1529/strict-fiber/go.sum deleted file mode 100644 index e2954b1efc..0000000000 --- a/internal/test/issues/issue-1529/strict-fiber/go.sum +++ /dev/null @@ -1,198 +0,0 @@ -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index 4d6ab516f5..e1324845b6 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -1,6 +1,6 @@ // Package issue1529 provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package issue1529 import ( diff --git a/internal/test/issues/issue1469/Makefile b/internal/test/issues/issue1469/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/internal/test/issues/issue1469/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/issues/issue1469/go.mod b/internal/test/issues/issue1469/go.mod deleted file mode 100644 index fbd28f728a..0000000000 --- a/internal/test/issues/issue1469/go.mod +++ /dev/null @@ -1,49 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue1469 - -go 1.24.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/gofiber/fiber/v2 v2.52.11 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.9 // 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.16 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.30.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/internal/test/issues/issue1469/go.sum b/internal/test/issues/issue1469/go.sum deleted file mode 100644 index e2954b1efc..0000000000 --- a/internal/test/issues/issue1469/go.sum +++ /dev/null @@ -1,198 +0,0 @@ -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/parameters/parameters_test.go b/internal/test/parameters/parameters_test.go index 29f6680e02..0635301dfa 100644 --- a/internal/test/parameters/parameters_test.go +++ b/internal/test/parameters/parameters_test.go @@ -9,7 +9,6 @@ import ( "github.com/oapi-codegen/testutil" "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -243,7 +242,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{ @@ -527,7 +525,6 @@ func doRequest(t *testing.T, e *echo.Echo, code int, req *http.Request) *httptes func TestClientPathParams(t *testing.T) { var ts testServer e := echo.New() - e.Use(middleware.Logger()) RegisterHandlers(e, &ts) server := "http://example.com" @@ -651,7 +648,6 @@ func TestClientPathParams(t *testing.T) { func TestClientQueryParams(t *testing.T) { var ts testServer e := echo.New() - e.Use(middleware.Logger()) RegisterHandlers(e, &ts) server := "http://example.com" diff --git a/internal/test/strict-server/fiber/Makefile b/internal/test/strict-server/fiber/Makefile deleted file mode 100644 index bb37d63394..0000000000 --- a/internal/test/strict-server/fiber/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 -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -define execute-if-go-124 -@{ \ -if [[ 24 -le $(GOMINOR) ]]; then \ - $1; \ -else \ - echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \ -fi \ -} -endef - -lint: - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...) - -lint-ci: - - $(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) - -generate: - $(call execute-if-go-124,go generate ./...) - -test: - $(call execute-if-go-124,go test -cover ./...) - -tidy: - $(call execute-if-go-124,go mod tidy) - -tidy-ci: - $(call execute-if-go-124,tidied -verbose) diff --git a/internal/test/strict-server/fiber/go.mod b/internal/test/strict-server/fiber/go.mod deleted file mode 100644 index a5442edf9d..0000000000 --- a/internal/test/strict-server/fiber/go.mod +++ /dev/null @@ -1,55 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/fiber - -go 1.24.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ - -replace github.com/oapi-codegen/oapi-codegen/v2/internal/test => ../.. - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/getkin/kin-openapi v0.133.0 - github.com/gofiber/fiber/v2 v2.52.11 - github.com/oapi-codegen/oapi-codegen/v2/internal/test v0.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.2.0 - github.com/oapi-codegen/testutil v1.0.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.9 // 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.16 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // 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/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.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/fiber/go.sum b/internal/test/strict-server/fiber/go.sum deleted file mode 100644 index 0d990d7990..0000000000 --- a/internal/test/strict-server/fiber/go.sum +++ /dev/null @@ -1,210 +0,0 @@ -github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/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/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/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/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/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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -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/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/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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= -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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/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/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= -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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -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/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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -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/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile index 48fe768e30..5ec0edd058 100644 --- a/internal/test/strict-server/stdhttp/Makefile +++ b/internal/test/strict-server/stdhttp/Makefile @@ -1,36 +1,17 @@ -SHELL:=/bin/bash - -YELLOW := \e[0;33m -RESET := \e[0;0m - -GOVER := $(shell go env GOVERSION) -GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.") - -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 ./...) + $(GOBIN)/golangci-lint run ./... lint-ci: - - $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m generate: - $(call execute-if-go-122,go generate ./...) + go generate ./... test: - $(call execute-if-go-122,go test -cover ./...) + go test -cover ./... tidy: - $(call execute-if-go-122,go mod tidy) + go mod tidy tidy-ci: - $(call execute-if-go-122,tidied -verbose) + tidied -verbose diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 4e0463b0c5..19a1b1cfb5 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -1,6 +1,6 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp -go 1.22.5 +go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ @@ -17,26 +17,26 @@ require ( require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.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.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.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 index 57cd609934..4680d9a4bb 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -6,8 +6,9 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/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= @@ -16,10 +17,12 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -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-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -39,22 +42,20 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/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/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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -82,16 +83,15 @@ 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/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/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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= +github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= 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= @@ -99,19 +99,19 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/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.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= 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/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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= @@ -119,13 +119,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= @@ -140,21 +140,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= 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= @@ -168,9 +168,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= From f459fd71fe71c475979bcda62181b14c2f4ee853 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Mon, 2 Mar 2026 09:02:20 +0000 Subject: [PATCH 204/293] docs: note that JSON Schema should be pinned Plus add Renovate configuration to update this in the future. --- README.md | 4 +++- renovate.json | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index da058e65a5..aa4dc860ee 100644 --- a/README.md +++ b/README.md @@ -112,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/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.6.0/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/). diff --git a/renovate.json b/renovate.json index 3af37f23db..8ac4d6e63c 100644 --- a/renovate.json +++ b/renovate.json @@ -69,5 +69,18 @@ "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" + } ] } From 717f4621327e3cab4705837c0045a7b8e6965e3c Mon Sep 17 00:00:00 2001 From: Jinu Thankachan <7960767+jinuthankachan@users.noreply.github.com> Date: Wed, 4 Mar 2026 00:54:57 +0530 Subject: [PATCH 205/293] feat: Support echo/v5 (#2188) * feat: server code generation for echo/v5 * feat/echov5-codegen (#6) * server code generation for echo/v5 * does not include: - strict-server for echo/v5 - middlewares for echo/v5 * fix: rename PathParam to Param for echo/v5 * fix: missing parts for strict server (#9) * fix: add the missing strict server generation * Clean up router imports Instead of hardcoding each router's framework and strict middleware imports directly in imports.tmpl with per-router conditional blocks, compute them in Go code via GenerateOptions.RouterImports() and pass them to the template as RouterImports. The template now uses a single range loop over .RouterImports, making it straightforward to add new routers without touching the template. Co-Authored-By: Claude Opus 4.6 * Add petstore-expanded/echo-v5 example Echo v5 version of the petstore-expanded example, in its own Go module (go 1.25.0) to avoid bumping the Go version of the shared examples module. Key differences from the echo (v4) example: - *echo.Context (pointer) instead of echo.Context (interface) - echo.NewHTTPError(code, message) takes exactly two args - No HTTPError.Internal field - EchoRouter returns echo.RouteInfo instead of *echo.Route - log.Fatal(e.Start(...)) instead of e.Logger.Fatal(...) Includes an inline OpenAPI request validation middleware (middleware/) adapted from echo-middleware for echo v5, since no published echo-v5 middleware package exists yet. Models and server stubs are placeholders until the codegen circular dependency for go:generate in isolated modules is resolved. Co-Authored-By: Claude Opus 4.6 * fix: skip echo-v5 example on Go < 1.25 The echo-v5 example requires Go 1.25+ (for echo/v5). When CI runs with GOTOOLCHAIN=local on Go 1.24, the module refuses to build. Add a Go version guard to the Makefile so all targets skip gracefully with an informational message on older Go versions. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: DanDagadita Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- cmd/oapi-codegen/oapi-codegen.go | 2 + configuration-schema.json | 16 +- examples/petstore-expanded/echo-v5/Makefile | 30 +++ .../echo-v5/api/models.cfg.yaml | 5 + .../echo-v5/api/models/models.gen.go | 46 ++++ .../echo-v5/api/petstore-server.gen.go | 247 ++++++++++++++++++ .../petstore-expanded/echo-v5/api/petstore.go | 146 +++++++++++ .../echo-v5/api/server.cfg.yaml | 9 + examples/petstore-expanded/echo-v5/go.mod | 42 +++ examples/petstore-expanded/echo-v5/go.sum | 191 ++++++++++++++ .../echo-v5/middleware/middleware.go | 226 ++++++++++++++++ .../petstore-expanded/echo-v5/petstore.go | 48 ++++ .../echo-v5/petstore_test.go | 152 +++++++++++ .../petstore-expanded/echo-v5/tools/tools.go | 8 + pkg/codegen/codegen.go | 17 ++ pkg/codegen/configuration.go | 53 ++++ pkg/codegen/operations.go | 9 + .../templates/echo/v5/echo-interface.tmpl | 7 + .../templates/echo/v5/echo-register.tmpl | 33 +++ .../templates/echo/v5/echo-wrappers.tmpl | 131 ++++++++++ pkg/codegen/templates/imports.tmpl | 14 +- .../templates/strict/strict-echo5.tmpl | 97 +++++++ 22 files changed, 1509 insertions(+), 20 deletions(-) create mode 100644 examples/petstore-expanded/echo-v5/Makefile create mode 100644 examples/petstore-expanded/echo-v5/api/models.cfg.yaml create mode 100644 examples/petstore-expanded/echo-v5/api/models/models.gen.go create mode 100644 examples/petstore-expanded/echo-v5/api/petstore-server.gen.go create mode 100644 examples/petstore-expanded/echo-v5/api/petstore.go create mode 100644 examples/petstore-expanded/echo-v5/api/server.cfg.yaml create mode 100644 examples/petstore-expanded/echo-v5/go.mod create mode 100644 examples/petstore-expanded/echo-v5/go.sum create mode 100644 examples/petstore-expanded/echo-v5/middleware/middleware.go create mode 100644 examples/petstore-expanded/echo-v5/petstore.go create mode 100644 examples/petstore-expanded/echo-v5/petstore_test.go create mode 100644 examples/petstore-expanded/echo-v5/tools/tools.go create mode 100644 pkg/codegen/templates/echo/v5/echo-interface.tmpl create mode 100644 pkg/codegen/templates/echo/v5/echo-register.tmpl create mode 100644 pkg/codegen/templates/echo/v5/echo-wrappers.tmpl create mode 100644 pkg/codegen/templates/strict/strict-echo5.tmpl diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index a3e43498c4..088821f5da 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -512,6 +512,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/configuration-schema.json b/configuration-schema.json index a81feefa3c..d25061e31b 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" @@ -197,9 +201,7 @@ "description": "DisableTypeAliasesForType allows defining which OpenAPI `type`s will explicitly not use type aliases", "items": { "type": "string", - "enum": [ - "array" - ] + "enum": ["array"] } }, "name-normalizer": { @@ -226,9 +228,7 @@ "default": true } }, - "required": [ - "path" - ] + "required": ["path"] }, "yaml-tags": { "type": "boolean", @@ -299,9 +299,7 @@ "type": "string" } }, - "required": [ - "package" - ] + "required": ["package"] }, "description": "AdditionalImports defines any additional Go imports to add to the generated code" }, diff --git a/examples/petstore-expanded/echo-v5/Makefile b/examples/petstore-expanded/echo-v5/Makefile new file mode 100644 index 0000000000..7eb1896df1 --- /dev/null +++ b/examples/petstore-expanded/echo-v5/Makefile @@ -0,0 +1,30 @@ +# This module requires Go 1.25+ (for echo/v5). Skip gracefully on older versions. +GO_VERSION := $(shell go version | sed 's/.*go\([0-9]*\)\.\([0-9]*\).*/\1\2/') +GO_125_OR_LATER := $(shell [ "$(GO_VERSION)" -ge 125 ] 2>/dev/null && echo yes || echo no) + +ifeq ($(GO_125_OR_LATER),yes) + +lint: + $(GOBIN)/golangci-lint run ./... + +lint-ci: + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m + +generate: + go generate ./... + +test: + go test -cover ./... + +tidy: + go mod tidy + +tidy-ci: + tidied -verbose + +else + +lint generate test tidy lint-ci tidy-ci: + @echo "Skipping echo-v5 example: requires Go 1.25+ (found $(shell go version))" + +endif 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..c99d14e424 --- /dev/null +++ b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go @@ -0,0 +1,247 @@ +// 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/gzip" + "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.BindQueryParameter("form", true, false, "tags", ctx.QueryParams(), ¶ms.Tags) + 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) + 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}) + 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}) + 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 +} + +// 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+"/pets", wrapper.FindPets) + router.POST(baseURL+"/pets", wrapper.AddPet) + router.DELETE(baseURL+"/pets/:id", wrapper.DeletePet) + router.GET(baseURL+"/pets/:id", wrapper.FindPetByID) + +} + +// Base64 encoded, gzipped, json marshaled Swagger object +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 +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/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/go.mod b/examples/petstore-expanded/echo-v5/go.mod new file mode 100644 index 0000000000..090320989f --- /dev/null +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -0,0 +1,42 @@ +module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5 + +go 1.25.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ + +require ( + github.com/getkin/kin-openapi v0.133.0 + github.com/labstack/echo/v5 v5.0.4 + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 + github.com/oapi-codegen/runtime v1.2.0 + github.com/oapi-codegen/testutil v1.1.0 + github.com/stretchr/testify v1.11.1 +) + +require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.42.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum new file mode 100644 index 0000000000..6cb9a23cb9 --- /dev/null +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -0,0 +1,191 @@ +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/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/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/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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/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/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/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +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/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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo/v5 v5.0.4 h1:ll3I/O8BifjMztj9dD1vx/peZQv8cR2CTUdQK6QxGGc= +github.com/labstack/echo/v5 v5.0.4/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= +github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +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/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/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= +github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= +github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= +github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/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..9742cc1939 --- /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.GetSwagger() + 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..61d0530a23 --- /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.GetSwagger() + 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-v5/tools/tools.go b/examples/petstore-expanded/echo-v5/tools/tools.go new file mode 100644 index 0000000000..8615cb4c57 --- /dev/null +++ b/examples/petstore-expanded/echo-v5/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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 281574a68f..3a77729bff 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -282,6 +282,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) @@ -426,6 +434,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 { @@ -1023,12 +1038,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) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 6f4df06a0f..0f35d13a90 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -50,6 +50,9 @@ func (o Configuration) Validate() error { if o.Generate.EchoServer { nServers++ } + if o.Generate.Echo5Server { + nServers++ + } if o.Generate.GorillaServer { nServers++ } @@ -112,6 +115,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 @@ -130,6 +135,54 @@ type GenerateOptions struct { 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"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictecho", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo"}) + } + case g.Echo5Server: + imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v5"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictecho5", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo/v5"}) + } + case g.ChiServer: + imports = append(imports, AdditionalImport{Package: "github.com/go-chi/chi/v5"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) + } + case g.GinServer: + imports = append(imports, AdditionalImport{Package: "github.com/gin-gonic/gin"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictgin", Package: "github.com/oapi-codegen/runtime/strictmiddleware/gin"}) + } + case g.GorillaServer: + imports = append(imports, AdditionalImport{Package: "github.com/gorilla/mux"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) + } + 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"}) + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictiris", Package: "github.com/oapi-codegen/runtime/strictmiddleware/iris"}) + } + case g.StdHTTPServer: + if g.Strict { + imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) + } + } + + return imports +} + func (oo GenerateOptions) Validate() map[string]string { return nil } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 3c639d22dc..5d9f735506 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -1089,6 +1089,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) { @@ -1126,6 +1132,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) } 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..1531eef866 --- /dev/null +++ b/pkg/codegen/templates/echo/v5/echo-interface.tmpl @@ -0,0 +1,7 @@ +// ServerInterface represents all server handlers. +type ServerInterface interface { +{{range .}}{{.SummaryAsComment }} +// ({{.Method}} {{.Path}}) +{{.OperationId}}(ctx *echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error +{{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..78de21b83e --- /dev/null +++ b/pkg/codegen/templates/echo/v5/echo-register.tmpl @@ -0,0 +1,33 @@ + + +// 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 +} + +// 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) { +{{if .}} + wrapper := ServerInterfaceWrapper{ + Handler: si, + } +{{end}} +{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) +{{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..9c1856167c --- /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}}// {{$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}}}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err)) + } +{{end}} +{{end}} + +{{range .SecurityDefinitions}} + ctx.Set({{.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.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.QueryParams(), ¶ms.{{.GoName}}) + 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}}}) + 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}}}) + 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}} diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl index 4d19422423..8c76dad36d 100644 --- a/pkg/codegen/templates/imports.tmpl +++ b/pkg/codegen/templates/imports.tmpl @@ -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/strict/strict-echo5.tmpl b/pkg/codegen/templates/strict/strict-echo5.tmpl new file mode 100644 index 0000000000..1f377bfdab --- /dev/null +++ b/pkg/codegen/templates/strict/strict-echo5.tmpl @@ -0,0 +1,97 @@ +type StrictHandlerFunc = strictecho5.StrictEchoHandlerFunc +type StrictMiddlewareFunc = strictecho5.StrictEchoMiddlewareFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +{{range .}} + {{$opid := .OperationId}} + // {{$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}}") { {{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.FormParams(); 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}} From 2b51e3fa64b0d62d53e95bc41d8e891eb99e4479 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 01:24:29 +0000 Subject: [PATCH 206/293] chore(deps): update oapi-codegen/actions action to v0.6.0 (.github/workflows) --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d5e0a1c6c..b1988ded17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,9 @@ permissions: contents: read jobs: build: - uses: oapi-codegen/actions/.github/workflows/ci.yml@75566d848d25021f137594c947f26171094fb511 # v0.5.0 + uses: oapi-codegen/actions/.github/workflows/ci.yml@6cf35d4f044f2663dae54547ff6d426e565beb48 # v0.6.0 with: - excluding_versions: '["1.22", "1.23"]' - lint_versions: '["1.25"]' + lint_versions: '["1.26"]' build-binaries: runs-on: ubuntu-latest From 05503dedf9075fb95a0faa98b4ae5ae8dacdb0c2 Mon Sep 17 00:00:00 2001 From: Bilel MEDIMEGH Date: Wed, 4 Mar 2026 23:29:24 +0100 Subject: [PATCH 207/293] AllOf : Only stop when merging schemas with multiple discriminators (#667) * AllOf : Only stop when merging schemas with multiple discriminators * test(codegen): add tests for discriminator propagation in allOf merges Covers all discriminator merge scenarios: - allOf: single discriminator propagated from either schema - allOf: both schemas having discriminators errors - allOf: no discriminators succeeds - non-allOf: any discriminator errors Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Bilel Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- pkg/codegen/merge_schemas.go | 11 +++++ pkg/codegen/merge_schemas_test.go | 68 +++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 pkg/codegen/merge_schemas_test.go diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index 39c499c7da..a2c979aa19 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -227,6 +227,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 } diff --git a/pkg/codegen/merge_schemas_test.go b/pkg/codegen/merge_schemas_test.go new file mode 100644 index 0000000000..9ba9a9f166 --- /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) + 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) + 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) + 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) + 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) + 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) + require.Error(t, err) + }) +} From a13ef41dfc5276e20728bc65b88399d16bee63ad Mon Sep 17 00:00:00 2001 From: nek023 <1830355+nek023@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:51:26 +0900 Subject: [PATCH 208/293] Generate types from components/securitySchemes to be used as a key in context.WithValue (#1187) * Generate types from components/securitySchemes for context.WithValue key * Update generated code * Fix security scheme context key type name mismatch The constants template used `sanitizeGoIdentity | lcFirst` to derive the context key type name, while the type definition in codegen.go used `LowercaseFirstCharacter(SchemaNameToTypeName(...))`. For security scheme names containing underscores (e.g. `api_key`, `petstore_auth`), these produced different results (`api_keyContextKey` vs `apiKeyContextKey`), causing compilation errors. Fix by exposing `SchemaNameToTypeName` as a template function and using it in the constants template so both paths produce the same type name. All affected generated files have been regenerated. Co-Authored-By: Claude Opus 4.6 * Add string() cast for typed security scheme keys in gin, iris, echo-v5 Gin, Iris, and Echo v5 use framework-level string-keyed maps for their Set() methods, which require a string argument. With the new typed context key constants, these calls fail to compile without an explicit string() conversion. Echo v4 already had this cast. Chi, gorilla, stdhttp, and fiber use context.WithValue (which accepts any) and are unaffected. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Jamie Tanna Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- .../authenticated-api/echo/api/api.gen.go | 9 ++++-- .../authenticated-api/stdhttp/api/api.gen.go | 5 +++- .../test/any_of/codegen/inline/openapi.gen.go | 7 +++-- .../any_of/codegen/ref_schema/openapi.gen.go | 7 +++-- internal/test/client/client.gen.go | 5 +++- internal/test/client/client.yaml | 4 +++ .../externalref/petstore/externalref.gen.go | 10 +++++-- internal/test/issues/issue-1087/api.gen.go | 3 ++ internal/test/schemas/schemas.gen.go | 25 +++++++++------- pkg/codegen/codegen.go | 29 +++++++++++++++++++ pkg/codegen/template_helpers.go | 1 + pkg/codegen/templates/constants.tmpl | 2 +- pkg/codegen/templates/echo/echo-wrappers.tmpl | 2 +- .../templates/echo/v5/echo-wrappers.tmpl | 2 +- .../templates/fiber/fiber-middleware.tmpl | 2 +- pkg/codegen/templates/gin/gin-wrappers.tmpl | 2 +- .../templates/iris/iris-middleware.tmpl | 2 +- pkg/codegen/utils.go | 12 ++++++++ 18 files changed, 101 insertions(+), 28 deletions(-) diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index 383ab5dc25..1dc357519f 100644 --- a/examples/authenticated-api/echo/api/api.gen.go +++ b/examples/authenticated-api/echo/api/api.gen.go @@ -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 @@ -425,7 +428,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 +439,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) diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index 91ced48c3d..bf3af4b293 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -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 diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index d3f34bec6e..4179ed9495 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -16,7 +16,7 @@ import ( ) const ( - ApiKeyAuthScopes = "ApiKeyAuth.Scopes" + ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes" ) // Cat This is a cat @@ -45,6 +45,9 @@ type Rat struct { Squeaks *bool `json:"squeaks,omitempty"` } +// apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme +type apiKeyAuthContextKey string + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -288,7 +291,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error { var err error - ctx.Set(ApiKeyAuthScopes, []string{}) + ctx.Set(string(ApiKeyAuthScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetPets(ctx) diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index 38f87c47be..d255052757 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -17,7 +17,7 @@ import ( ) const ( - ApiKeyAuthScopes = "ApiKeyAuth.Scopes" + ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes" ) // Cat This is a cat @@ -56,6 +56,9 @@ type Rat struct { 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 @@ -380,7 +383,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error { var err error - ctx.Set(ApiKeyAuthScopes, []string{}) + ctx.Set(string(ApiKeyAuthScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetPets(ctx) diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go index 275c72cf0f..17135a2ea7 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{} 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/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index e8102f0d28..e4b540a404 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -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. @@ -166,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 diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go index 3c408cc8f9..7c154d9115 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 diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 9c0871cb34..f8293f4608 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -25,7 +25,7 @@ import ( ) const ( - Access_tokenScopes = "access_token.Scopes" + Access_tokenScopes accessTokenContextKey = "access_token.Scopes" ) // Defines values for EnumInObjInArrayVal. @@ -111,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{} @@ -1418,7 +1421,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) @@ -1429,7 +1432,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) @@ -1440,7 +1443,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) @@ -1451,7 +1454,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) @@ -1469,7 +1472,7 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error { 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) @@ -1487,7 +1490,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { 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) @@ -1498,7 +1501,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) @@ -1516,7 +1519,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { 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) @@ -1527,7 +1530,7 @@ 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 @@ -1547,7 +1550,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) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 3a77729bff..6aedce1805 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -561,6 +561,12 @@ 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...) + + 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...) } // Go through all operations, and add their types to allTypes, so that we can @@ -847,6 +853,29 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open 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 +} + // GenerateTypes passes a bunch of types to the template engine, and buffers // its output into a string. func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) { diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index e4d932116a..19c533f1e6 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -350,6 +350,7 @@ var TemplateFunctions = template.FuncMap{ "title": titleCaser.String, "stripNewLines": stripNewLines, "sanitizeGoIdentity": SanitizeGoIdentity, + "schemaNameToTypeName": SchemaNameToTypeName, "toGoString": StringToGoString, "toGoComment": StringWithTypeNameToGoComment, diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index 1c8cbd4922..df434e5377 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}} diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index 584a21f26c..a086d75d4e 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -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}} diff --git a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl index 9c1856167c..9f7d608dda 100644 --- a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl @@ -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}} diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 63bc2cb831..eab735e5e6 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -36,7 +36,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{end}} {{range .SecurityDefinitions}} - c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}}) + c.Context().SetUserValue(({{.ProviderName | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 272e2ec609..e18c0d644c 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -40,7 +40,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}} diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index 0bc6b1229b..7ee4ce9b2b 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -35,7 +35,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}} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index adfeb7c89f..b6fb91985f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -405,6 +405,18 @@ func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) { return 0, false } +// SortedParameterKeys returns sorted keys for a SecuritySchemeRef dict +func SortedSecuritySchemeKeys(dict map[string]*openapi3.SecuritySchemeRef) []string { + keys := make([]string, len(dict)) + i := 0 + for key := range dict { + keys[i] = key + i++ + } + sort.Strings(keys) + return keys +} + // StringInArray checks whether the specified string is present in an array // of strings func StringInArray(str string, array []string) bool { From 5b832190e39a030ac999279fbb2d983f2cc73606 Mon Sep 17 00:00:00 2001 From: Sean Cunniffe <72317985+sean-cunniffe@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:54:35 +1100 Subject: [PATCH 209/293] fix: allow response error handler to set status code (#1963) * fix: allow response error handler to set status code change the order the visit response body function sets the status code and content type so if an error occurs during json marshalling the response error handler can set the status code * fix: buffer JSON responses before writing headers JSON responses in strict server Visit*Response functions are now encoded to a bytes.Buffer before setting headers and calling WriteHeader. This ensures that if JSON encoding fails, nothing has been written to the ResponseWriter, allowing ResponseErrorHandlerFunc to set an appropriate status code (e.g. 500 instead of 200). Non-JSON content types (text, formdata, multipart, binary/io.Reader) retain the original headers-first ordering since their write patterns do not benefit from buffering. Adds regression tests for all content type paths and an integration test verifying that ResponseErrorHandlerFunc can set the status code when JSON encoding fails. Co-Authored-By: Claude Sonnet 4.6 * Address Greptile feedback Also buffer formdata responses before writing headers Apply the same marshal-before-headers pattern to Formdata responses: runtime.MarshalForm is called before setting Content-Type or calling WriteHeader, so if marshalling fails the error handler can still set an appropriate status code. Adds a regression test for the formdata encoding error path. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Sonnet 4.6 --- .../issues/issue-1093/api/child/child.gen.go | 9 +- .../issue-1093/api/parent/parent.gen.go | 9 +- .../issue-1208-1209/issue-multi-json.gen.go | 36 +- .../test/issues/issue-1212/pkg1/pkg1.gen.go | 1 + .../issue-1378/bionicle/bionicle.gen.go | 18 +- .../issue-1378/fooservice/fooservice.gen.go | 18 +- .../issue-1529/strict-echo/issue1529.gen.go | 27 +- internal/test/issues/issue-1676/ping.gen.go | 1 + internal/test/issues/issue-1963/config.yaml | 6 + internal/test/issues/issue-1963/generate.go | 3 + .../test/issues/issue-1963/issue1963.gen.go | 590 ++++++++++++++++++ .../test/issues/issue-1963/issue1963_test.go | 239 +++++++ internal/test/issues/issue-1963/spec.yaml | 105 ++++ .../test/issues/issue-2113/gen/api/api.gen.go | 28 +- .../test/issues/issue-2190/issue2190.gen.go | 11 +- .../gen/spec_base/issue.gen.go | 19 +- internal/test/strict-server/chi/server.gen.go | 97 ++- .../test/strict-server/echo/server.gen.go | 97 ++- internal/test/strict-server/gin/server.gen.go | 97 ++- .../test/strict-server/gorilla/server.gen.go | 97 ++- .../test/strict-server/stdhttp/server.gen.go | 97 ++- .../templates/strict/strict-interface.tmpl | 72 ++- 22 files changed, 1482 insertions(+), 195 deletions(-) create mode 100644 internal/test/issues/issue-1963/config.yaml create mode 100644 internal/test/issues/issue-1963/generate.go create mode 100644 internal/test/issues/issue-1963/issue1963.gen.go create mode 100644 internal/test/issues/issue-1963/issue1963_test.go create mode 100644 internal/test/issues/issue-1963/spec.yaml 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 203fad36e8..d6a7ae9bfc 100644 --- a/internal/test/issues/issue-1093/api/child/child.gen.go +++ b/internal/test/issues/issue-1093/api/child/child.gen.go @@ -90,10 +90,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. 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..462818dea7 100644 --- a/internal/test/issues/issue-1093/api/parent/parent.gen.go +++ b/internal/test/issues/issue-1093/api/parent/parent.gen.go @@ -95,10 +95,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. 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..c93e087717 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 @@ -353,19 +353,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 +383,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 +399,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. diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index c24850b199..d2922a4a85 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -302,6 +302,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) diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index 863c5fd380..c809c52904 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -200,10 +200,15 @@ 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 { @@ -211,10 +216,15 @@ type GetBionicleName400JSONResponse struct { } 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. diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index d076409c14..a6416cfdf2 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -193,10 +193,15 @@ 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type GetBionicleName400JSONResponse struct { @@ -204,10 +209,15 @@ type GetBionicleName400JSONResponse struct { } 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. diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index cd5260fae4..46655a12d3 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -323,28 +323,43 @@ type TestResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, 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) - - return json.NewEncoder(w).Encode(response) + _, 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } // StrictServerInterface represents all server handlers. diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go index dcfddc3bc6..19a354080a 100644 --- a/internal/test/issues/issue-1676/ping.gen.go +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -177,6 +177,7 @@ type GetPing200TextResponse struct { } func (response GetPing200TextResponse) VisitGetPingResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.Header().Set("MyHeader", fmt.Sprint(response.Headers.MyHeader)) w.WriteHeader(200) 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..c47fb4aba0 --- /dev/null +++ b/internal/test/issues/issue-1963/issue1963.gen.go @@ -0,0 +1,590 @@ +//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" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + +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("POST "+options.BaseURL+"/binary", wrapper.BinaryEndpoint) + m.HandleFunc("POST "+options.BaseURL+"/formdata", wrapper.FormdataEndpoint) + m.HandleFunc("POST "+options.BaseURL+"/json", wrapper.JsonEndpoint) + m.HandleFunc("POST "+options.BaseURL+"/multipart", wrapper.MultipartEndpoint) + m.HandleFunc("POST "+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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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-2113/gen/api/api.gen.go b/internal/test/issues/issue-2113/gen/api/api.gen.go index 6562a7f30d..626e5ea1f6 100644 --- a/internal/test/issues/issue-2113/gen/api/api.gen.go +++ b/internal/test/issues/issue-2113/gen/api/api.gen.go @@ -4,6 +4,7 @@ package api import ( + "bytes" "context" "encoding/json" "fmt" @@ -183,19 +184,29 @@ type ListThingsResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type ListThings400JSONResponse struct{ externalRef0.StandardError } 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type ListThingsdefaultJSONResponse struct { @@ -204,10 +215,15 @@ type ListThingsdefaultJSONResponse struct { } 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) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } // StrictServerInterface represents all server handlers. diff --git a/internal/test/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index c22e32724c..409eba372f 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -6,6 +6,7 @@ package issue2190 import ( + "bytes" "context" "encoding/json" "fmt" @@ -409,15 +410,21 @@ type GetTestResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, 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) 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..f96b78c9b2 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" @@ -218,10 +219,15 @@ type PostInvalidExtRefTroubleResponseObject interface { type PostInvalidExtRefTrouble300JSONResponse struct{ externalRef0.Pascal } 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 +245,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. diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index a7c569b2c5..01ef76a0c7 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -593,10 +593,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 @@ -627,6 +632,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) @@ -662,6 +668,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) @@ -700,24 +707,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 { @@ -726,6 +738,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)) @@ -743,6 +756,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) @@ -753,6 +767,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) @@ -778,10 +793,15 @@ type RequiredJSONBodyResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RequiredJSONBody400Response = BadrequestResponse @@ -811,6 +831,7 @@ type RequiredTextBodyResponseObject interface { type RequiredTextBody200TextResponse string func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(200) @@ -845,6 +866,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) @@ -863,12 +885,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 @@ -898,6 +925,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) @@ -935,6 +963,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)) @@ -980,6 +1009,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)) @@ -1036,15 +1066,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 @@ -1083,12 +1113,17 @@ 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)) w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } type HeadersExample400Response = BadrequestResponse @@ -1126,12 +1161,17 @@ 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 { @@ -1142,12 +1182,17 @@ type UnionExample200JSONResponse struct { } 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 diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index e8e335c74a..9770f43472 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -315,10 +315,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 @@ -349,6 +354,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) @@ -384,6 +390,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) @@ -422,24 +429,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 { @@ -448,6 +460,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)) @@ -465,6 +478,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) @@ -475,6 +489,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) @@ -500,10 +515,15 @@ type RequiredJSONBodyResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RequiredJSONBody400Response = BadrequestResponse @@ -533,6 +553,7 @@ type RequiredTextBodyResponseObject interface { type RequiredTextBody200TextResponse string func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(200) @@ -567,6 +588,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) @@ -585,12 +607,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 @@ -620,6 +647,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) @@ -657,6 +685,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)) @@ -702,6 +731,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)) @@ -758,15 +788,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 @@ -805,12 +835,17 @@ 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)) w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } type HeadersExample400Response = BadrequestResponse @@ -848,12 +883,17 @@ 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 { @@ -864,12 +904,17 @@ type UnionExample200JSONResponse struct { } 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 diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index b664de93d3..25b3f654db 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -388,10 +388,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 @@ -422,6 +427,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) @@ -457,6 +463,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) @@ -495,24 +502,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 { @@ -521,6 +533,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)) @@ -538,6 +551,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) @@ -548,6 +562,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) @@ -573,10 +588,15 @@ type RequiredJSONBodyResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RequiredJSONBody400Response = BadrequestResponse @@ -606,6 +626,7 @@ type RequiredTextBodyResponseObject interface { type RequiredTextBody200TextResponse string func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(200) @@ -640,6 +661,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) @@ -658,12 +680,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 @@ -693,6 +720,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) @@ -730,6 +758,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)) @@ -775,6 +804,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)) @@ -831,15 +861,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,12 +908,17 @@ 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)) w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } type HeadersExample400Response = BadrequestResponse @@ -921,12 +956,17 @@ 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 { @@ -937,12 +977,17 @@ type UnionExample200JSONResponse struct { } 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 diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index a141223fc5..c4cf39d483 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -504,10 +504,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 @@ -538,6 +543,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) @@ -573,6 +579,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) @@ -611,24 +618,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 { @@ -637,6 +649,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)) @@ -654,6 +667,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) @@ -664,6 +678,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) @@ -689,10 +704,15 @@ type RequiredJSONBodyResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RequiredJSONBody400Response = BadrequestResponse @@ -722,6 +742,7 @@ type RequiredTextBodyResponseObject interface { type RequiredTextBody200TextResponse string func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(200) @@ -756,6 +777,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) @@ -774,12 +796,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 @@ -809,6 +836,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) @@ -846,6 +874,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)) @@ -891,6 +920,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)) @@ -947,15 +977,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 @@ -994,12 +1024,17 @@ 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)) w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } type HeadersExample400Response = BadrequestResponse @@ -1037,12 +1072,17 @@ 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 { @@ -1053,12 +1093,17 @@ type UnionExample200JSONResponse struct { } 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 diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 2d6b8642ee..99160f5f0b 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -499,10 +499,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 @@ -533,6 +538,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) @@ -568,6 +574,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) @@ -606,24 +613,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 { @@ -632,6 +644,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)) @@ -649,6 +662,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) @@ -659,6 +673,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) @@ -684,10 +699,15 @@ type RequiredJSONBodyResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } type RequiredJSONBody400Response = BadrequestResponse @@ -717,6 +737,7 @@ type RequiredTextBodyResponseObject interface { type RequiredTextBody200TextResponse string func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(200) @@ -751,6 +772,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) @@ -769,12 +791,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 @@ -804,6 +831,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) @@ -841,6 +869,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)) @@ -886,6 +915,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)) @@ -942,15 +972,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 @@ -989,12 +1019,17 @@ 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)) w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response.Body) + _, err := buf.WriteTo(w) + return err } type HeadersExample400Response = BadrequestResponse @@ -1032,12 +1067,17 @@ 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 { @@ -1048,12 +1088,17 @@ type UnionExample200JSONResponse struct { } 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 diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 62f3d4d9c6..ab56514e8a 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -74,40 +74,58 @@ {{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 | toGoString}}{{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 $hasUnionElements}}.union{{end}}); err != nil { + return err + } + w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}}) + {{range $headers -}} + w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) + {{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 -}} + w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) + {{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}}", 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 -}} + w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}})) + {{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() + } + _, err := io.Copy(w, response.Body) + return err + {{end}}{{/* if eq .NameTag "Text" */ -}} + {{end}}{{/* if .IsJSON */ -}} } {{end}} From 524f05360eb0c01b05cb09da78450404712d1adc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:50:43 -0800 Subject: [PATCH 210/293] chore(deps): update release-drafter/release-drafter action to v6.3.0 (.github/workflows) (#2282) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 7b03a27d7a..36d0c96320 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@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0 + - uses: release-drafter/release-drafter@00ce30b0ce8a4d67bccfca59421cdf6c55dd0784 # v6.3.0 with: name: next tag: next From e7059640da248633d129ec38c17fdc982396bcdb Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 12 Mar 2026 08:10:39 +0000 Subject: [PATCH 211/293] fix(client): correctly marshal `text/plain` requests (#1975) * fix(client): correctly marshal `text/plain` requests As noted in #1914, there are cases where trying to interact with a `text/plain` endpoint that requires input, for instance when receiving a UUID, may not render correctly. We should first check if the type is a `Stringer`, aka has a `String()` method, and use that - otherwise use `fmt.Sprintf("%v", ...)` to generate a string type. Via [0], we can make sure that we wrap the generated type in an empty `interface`, so we can perform the type assertion. This also adds a test case to validate the functionality for: - a UUID, which has a `String()` method - a `float32`, which is a primitive datatype that needs to use `fmt.Sprintf` Co-authored-by: claude-sonnet:3.7-thinking Closes #1914. [0]: https://www.jvt.me/posts/2025/05/10/go-type-assertion-concrete/ * fix(client): add three-tier text/plain body marshaling for #1914 For text/plain request bodies, the generated client code now: 1. Checks if the body type implements fmt.Stringer and uses String() 2. Falls back to fmt.Sprintf("%v", body) for primitive types 3. Returns an error for complex types (objects, arrays, composed schemas), directing the user to implement a String() method Adds Schema.IsPrimitive() to distinguish primitive OpenAPI types (string, integer, number, boolean) from complex ones at codegen time. Closes #1914. Co-Authored-By: Claude Sonnet 4.6 * Apply suggestion from @gaiaz-iusipov Co-authored-by: Gaiaz Iusipov * Update generated files --------- Co-authored-by: claude-sonnet:3.7-thinking Co-authored-by: Jamie Tanna Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Marcin Romaszewicz Co-authored-by: Gaiaz Iusipov --- internal/test/issues/issue-1914/cfg.yaml | 6 + internal/test/issues/issue-1914/client.gen.go | 401 ++++++++++++++++++ .../test/issues/issue-1914/client_test.go | 44 ++ internal/test/issues/issue-1914/generate.go | 3 + internal/test/issues/issue-1914/spec.yaml | 19 + .../test/strict-server/client/client.gen.go | 18 +- pkg/codegen/schema.go | 11 + pkg/codegen/templates/client.tmpl | 10 +- 8 files changed, 508 insertions(+), 4 deletions(-) create mode 100644 internal/test/issues/issue-1914/cfg.yaml create mode 100644 internal/test/issues/issue-1914/client.gen.go create mode 100644 internal/test/issues/issue-1914/client_test.go create mode 100644 internal/test/issues/issue-1914/generate.go create mode 100644 internal/test/issues/issue-1914/spec.yaml 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..bdbe1797d2 --- /dev/null +++ b/internal/test/issues/issue-1914/client.gen.go @@ -0,0 +1,401 @@ +// 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("POST", 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("POST", 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 +} + +// 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 +} + +type PostPet1234Response struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +// 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/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index b189ff5adf..fa66382d70 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -642,7 +642,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) } @@ -718,7 +722,11 @@ func NewRequiredJSONBodyRequestWithBody(server string, contentType string, body // NewRequiredTextBodyRequestWithTextBody calls the generic RequiredTextBody builder with text/plain body func NewRequiredTextBodyRequestWithTextBody(server string, body RequiredTextBodyTextRequestBody) (*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 NewRequiredTextBodyRequestWithBody(server, "text/plain", bodyReader) } @@ -828,7 +836,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) } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index ff72d23b6b..e6e1b2a3a1 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -42,6 +42,17 @@ type Schema struct { } +// 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 != "" } diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 24410dfae6..e172642825 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -148,7 +148,15 @@ 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) } From 8650f43d2ccd299534796c3ae510b197b1640ca9 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 12 Mar 2026 09:36:08 -0700 Subject: [PATCH 212/293] Fix typo in echo-v5 middleware import (#2285) Fixes: 2281 --- pkg/codegen/configuration.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 0f35d13a90..1db5deff02 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -149,7 +149,7 @@ func (g GenerateOptions) RouterImports() []AdditionalImport { case g.Echo5Server: imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v5"}) if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictecho5", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo/v5"}) + imports = append(imports, AdditionalImport{Alias: "strictecho5", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo-v5"}) } case g.ChiServer: imports = append(imports, AdditionalImport{Package: "github.com/go-chi/chi/v5"}) From 00a90b7a03f4cdc8bc8daf16eea6868b48c7d278 Mon Sep 17 00:00:00 2001 From: Ilia Rassadin <141235148+ilia-rassadin-rn@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:37:12 +0100 Subject: [PATCH 213/293] fix(deps): update module github.com/getkin/kin-openapi to v0.134.0 (go.mod) (#2295) * fix: support kin-openapi v0.134.0 MappingRef type change In kin-openapi v0.134.0, Discriminator.Mapping changed from map[string]string to StringMap[MappingRef], where MappingRef is type MappingRef SchemaRef (a struct with a Ref string field). This caused a compile error in generateUnion where v (MappingRef) was compared directly against element.Ref (string). Fix by comparing v.Ref instead. Bump kin-openapi dependency to v0.134.0. * fix(deps): update module github.com/getkin/kin-openapi to v0.134.0 (go.mod) * fixup! fix(deps): update module github.com/getkin/kin-openapi to v0.134.0 (go.mod) --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jamie Tanna --- examples/authenticated-api/stdhttp/go.mod | 6 +++--- examples/authenticated-api/stdhttp/go.sum | 12 ++++++------ examples/go.mod | 6 +++--- examples/go.sum | 12 ++++++------ examples/minimal-server/stdhttp/go.mod | 6 +++--- examples/minimal-server/stdhttp/go.sum | 12 ++++++------ examples/petstore-expanded/echo-v5/go.mod | 6 +++--- examples/petstore-expanded/echo-v5/go.sum | 12 ++++++------ examples/petstore-expanded/stdhttp/go.mod | 6 +++--- examples/petstore-expanded/stdhttp/go.sum | 12 ++++++------ go.mod | 6 +++--- go.sum | 12 ++++++------ internal/test/go.mod | 6 +++--- internal/test/go.sum | 12 ++++++------ internal/test/strict-server/stdhttp/go.mod | 6 +++--- internal/test/strict-server/stdhttp/go.sum | 12 ++++++------ pkg/codegen/schema.go | 2 +- 17 files changed, 73 insertions(+), 73 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 64d200dc01..456ea79cc6 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 github.com/lestrrat-go/jwx v1.2.31 github.com/oapi-codegen/nethttp-middleware v1.1.2 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 @@ -29,8 +29,8 @@ require ( github.com/lestrrat-go/option v1.0.1 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 372e7efe62..190a8206db 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -77,10 +77,10 @@ github.com/oapi-codegen/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/examples/go.mod b/examples/go.mod index 0b92bb2e87..998f23e291 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 github.com/gin-gonic/gin v1.11.0 github.com/go-chi/chi/v5 v5.2.5 github.com/gofiber/fiber/v2 v2.52.12 @@ -81,8 +81,8 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 180de2d19d..49512be9b8 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -50,8 +50,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= @@ -207,10 +207,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 98ad587fc4..acb4ea2c04 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -8,14 +8,14 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect + github.com/getkin/kin-openapi v0.134.0 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index e5ac6ef8cc..f2ff34e742 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -11,8 +11,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -54,10 +54,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod index 090320989f..09e9022013 100644 --- a/examples/petstore-expanded/echo-v5/go.mod +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -5,7 +5,7 @@ go 1.25.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 github.com/labstack/echo/v5 v5.0.4 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 github.com/oapi-codegen/runtime v1.2.0 @@ -24,8 +24,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum index 6cb9a23cb9..15fb93d7b0 100644 --- a/examples/petstore-expanded/echo-v5/go.sum +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -69,10 +69,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 3922deb19e..481ce10be2 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 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.2.0 @@ -24,8 +24,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 677ca72245..9976dfce36 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -69,10 +69,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/go.mod b/go.mod index ce84f98d4e..d6c392af11 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.3 toolchain go1.24.4 require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.11.1 golang.org/x/mod v0.33.0 @@ -23,8 +23,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/go.sum b/go.sum index 8e99a7a7fd..c7599ec79b 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -54,10 +54,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 6f70f67ca3..3883c7548e 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.133.0 + github.com/getkin/kin-openapi v0.134.0 github.com/gin-gonic/gin v1.11.0 github.com/go-chi/chi/v5 v5.2.5 github.com/gofiber/fiber/v2 v2.52.12 @@ -70,8 +70,8 @@ require ( 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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index d4d3ba66ee..e4e6e813f1 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -48,8 +48,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= @@ -184,10 +184,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 19a1b1cfb5..443f10af94 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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.133.0 + github.com/getkin/kin-openapi v0.134.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.2.0 @@ -25,8 +25,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect - github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect + github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 4680d9a4bb..5ba1c74b30 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= +github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -65,10 +65,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= -github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= -github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= +github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= +github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/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= diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index e6e1b2a3a1..799e327dea 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -897,7 +897,7 @@ 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 } From 28e3bc133939a35aa781eb76b331734685e31e00 Mon Sep 17 00:00:00 2001 From: Yata <84038514+YATAHAKI@users.noreply.github.com> Date: Mon, 23 Mar 2026 21:42:52 +0300 Subject: [PATCH 214/293] fix: getting cookie in fiber middleware (#2062) --- pkg/codegen/templates/fiber/fiber-middleware.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index eab735e5e6..dc48266696 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -127,7 +127,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{range .CookieParams}} var cookie string - if cookie = c.Cookies("{{.ParamName}}"); cookie == "" { + if cookie = c.Cookies("{{.ParamName}}"); cookie != "" { {{- if .IsPassThrough}} params.{{.GoName}} = {{if .HasOptionalPointer}}}&{{end}}cookie From fc65e09d0015f9b132ace66ac74bad2e0d0cb585 Mon Sep 17 00:00:00 2001 From: Kazusa Sugeno <52691115+imsugeno@users.noreply.github.com> Date: Tue, 24 Mar 2026 04:30:15 +0900 Subject: [PATCH 215/293] feat: use http.MethodXXX constants instead of string literals in generated code (#2294) * feat: use http.MethodXXX constants instead of string literals Add httpMethodConstant template helper that converts HTTP method strings (e.g. "GET") to net/http constants (e.g. http.MethodGet) and apply it to the client, gorilla, and stdhttp templates. Refs #659 * chore: regenerate code with http.MethodXXX constants Run make generate to update all generated files with the new http.MethodXXX constants in place of string literals. --------- Co-authored-by: Marcin Romaszewicz --- .../authenticated-api/stdhttp/api/api.gen.go | 8 ++-- .../minimal-server/stdhttp/api/ping.gen.go | 2 +- .../stdhttp/api/petstore.gen.go | 8 ++-- .../test/any_of/codegen/inline/openapi.gen.go | 2 +- .../any_of/codegen/ref_schema/openapi.gen.go | 2 +- internal/test/any_of/param/param.gen.go | 2 +- internal/test/client/client.gen.go | 16 +++---- internal/test/issues/issue-1039/client.gen.go | 2 +- internal/test/issues/issue-1087/api.gen.go | 2 +- internal/test/issues/issue-1180/issue.gen.go | 2 +- .../test/issues/issue-1182/pkg1/pkg1.gen.go | 2 +- .../test/issues/issue-1189/issue1189.gen.go | 2 +- .../issue-1208-1209/issue-multi-json.gen.go | 2 +- .../test/issues/issue-1212/pkg1/pkg1.gen.go | 2 +- .../test/issues/issue-1298/issue1298.gen.go | 2 +- .../issue-1378/bionicle/bionicle.gen.go | 2 +- .../issue-1378/fooservice/fooservice.gen.go | 2 +- .../test/issues/issue-1397/issue1397.gen.go | 2 +- .../issue-1529/strict-echo/issue1529.gen.go | 2 +- .../issue-1529/strict-fiber/issue1529.gen.go | 2 +- .../issue-1529/strict-iris/issue1529.gen.go | 2 +- internal/test/issues/issue-1676/ping.gen.go | 2 +- internal/test/issues/issue-1914/client.gen.go | 4 +- .../test/issues/issue-1963/issue1963.gen.go | 10 ++--- .../issues/issue-2031/prefer/issue2031.gen.go | 2 +- .../test/issues/issue-2190/issue2190.gen.go | 4 +- .../test/issues/issue-2232/issue2232.gen.go | 2 +- .../test/issues/issue-2238/issue2238.gen.go | 2 +- internal/test/issues/issue-312/issue.gen.go | 4 +- internal/test/issues/issue-52/issue.gen.go | 2 +- .../issue-grab_import_names/issue.gen.go | 2 +- .../issue-illegal_enum_names/issue.gen.go | 2 +- internal/test/issues/issue240/client.gen.go | 4 +- .../name_conflict_resolution.gen.go | 36 ++++++++-------- .../name_normalizer.gen.go | 4 +- .../name_normalizer.gen.go | 4 +- .../name_normalizer.gen.go | 4 +- .../to-camel-case/name_normalizer.gen.go | 4 +- .../unset/name_normalizer.gen.go | 4 +- internal/test/parameters/parameters.gen.go | 42 +++++++++---------- internal/test/schemas/schemas.gen.go | 20 ++++----- .../test/strict-server/client/client.gen.go | 28 ++++++------- .../test/strict-server/gorilla/server.gen.go | 28 ++++++------- .../test/strict-server/stdhttp/server.gen.go | 28 ++++++------- pkg/codegen/template_helpers.go | 26 ++++++++++++ pkg/codegen/templates/client.tmpl | 2 +- .../templates/gorilla/gorilla-register.tmpl | 2 +- .../templates/stdhttp/std-http-handler.tmpl | 2 +- 48 files changed, 184 insertions(+), 158 deletions(-) diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index bf3af4b293..da76ee17b2 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -188,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 } @@ -226,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 } @@ -589,8 +589,8 @@ 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 } diff --git a/examples/minimal-server/stdhttp/api/ping.gen.go b/examples/minimal-server/stdhttp/api/ping.gen.go index 794f8d817f..0b1984332e 100644 --- a/examples/minimal-server/stdhttp/api/ping.gen.go +++ b/examples/minimal-server/stdhttp/api/ping.gen.go @@ -165,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/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index 4f0c52be9d..1581d7705f 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -305,10 +305,10 @@ 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 } diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index 4179ed9495..3f85d9bc2f 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -156,7 +156,7 @@ func NewGetPetsRequest(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 } diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index d255052757..05d763e6ac 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -255,7 +255,7 @@ func NewGetPetsRequest(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 } diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 483228d045..2a082006cc 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -319,7 +319,7 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) if err != nil { return nil, err } diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go index 17135a2ea7..13fe998b9a 100644 --- a/internal/test/client/client.gen.go +++ b/internal/test/client/client.gen.go @@ -305,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 } @@ -334,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 } @@ -372,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 } @@ -401,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 } @@ -428,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 } @@ -457,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 } @@ -484,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 } @@ -522,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 } diff --git a/internal/test/issues/issue-1039/client.gen.go b/internal/test/issues/issue-1039/client.gen.go index 3114f29862..43cca8d279 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 } diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go index 7c154d9115..cf944315f5 100644 --- a/internal/test/issues/issue-1087/api.gen.go +++ b/internal/test/issues/issue-1087/api.gen.go @@ -144,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 } diff --git a/internal/test/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index 26e358477a..dd7f244904 100644 --- a/internal/test/issues/issue-1180/issue.gen.go +++ b/internal/test/issues/issue-1180/issue.gen.go @@ -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 } diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index 0b01c5738e..4773438107 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -129,7 +129,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 } diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index c6e0579fd5..8b0aa4c209 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -339,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 } 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 c93e087717..50ec7337a5 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 @@ -145,7 +145,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 } diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index d2922a4a85..50244c424f 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -131,7 +131,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 } diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index 2e5a48dc57..a45d921e58 100644 --- a/internal/test/issues/issue-1298/issue1298.gen.go +++ b/internal/test/issues/issue-1298/issue1298.gen.go @@ -160,7 +160,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 } diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index c809c52904..c18418eaef 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -184,7 +184,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 } diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index a6416cfdf2..966de191e5 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -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 } diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index 11bc883db2..a799293922 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -201,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 } diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index 46655a12d3..d392436a89 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -132,7 +132,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 } diff --git a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index e1324845b6..f4fe591c04 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -131,7 +131,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 } diff --git a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go index a214576e80..6d03eef9ce 100644 --- a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -132,7 +132,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 } diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go index 19a354080a..53fa480501 100644 --- a/internal/test/issues/issue-1676/ping.gen.go +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -155,7 +155,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/internal/test/issues/issue-1914/client.gen.go b/internal/test/issues/issue-1914/client.gen.go index bdbe1797d2..5628fff078 100644 --- a/internal/test/issues/issue-1914/client.gen.go +++ b/internal/test/issues/issue-1914/client.gen.go @@ -188,7 +188,7 @@ func NewPostPetRequestWithBody(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 } @@ -228,7 +228,7 @@ func NewPostPet1234RequestWithBody(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 } diff --git a/internal/test/issues/issue-1963/issue1963.gen.go b/internal/test/issues/issue-1963/issue1963.gen.go index c47fb4aba0..9c5b00bd9b 100644 --- a/internal/test/issues/issue-1963/issue1963.gen.go +++ b/internal/test/issues/issue-1963/issue1963.gen.go @@ -266,11 +266,11 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H ErrorHandlerFunc: options.ErrorHandlerFunc, } - m.HandleFunc("POST "+options.BaseURL+"/binary", wrapper.BinaryEndpoint) - m.HandleFunc("POST "+options.BaseURL+"/formdata", wrapper.FormdataEndpoint) - m.HandleFunc("POST "+options.BaseURL+"/json", wrapper.JsonEndpoint) - m.HandleFunc("POST "+options.BaseURL+"/multipart", wrapper.MultipartEndpoint) - m.HandleFunc("POST "+options.BaseURL+"/text", wrapper.TextEndpoint) + 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 } diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go index 6144c0b4be..2aeb2c4b88 100644 --- a/internal/test/issues/issue-2031/prefer/issue2031.gen.go +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -149,7 +149,7 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) if err != nil { return nil, err } diff --git a/internal/test/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index 409eba372f..d911a8474c 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -129,7 +129,7 @@ func NewGetTestRequest(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 } @@ -391,7 +391,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H ErrorHandlerFunc: options.ErrorHandlerFunc, } - m.HandleFunc("GET "+options.BaseURL+"/v1/test", wrapper.GetTest) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/v1/test", wrapper.GetTest) return m } diff --git a/internal/test/issues/issue-2232/issue2232.gen.go b/internal/test/issues/issue-2232/issue2232.gen.go index 1820ba5f29..9b98648470 100644 --- a/internal/test/issues/issue-2232/issue2232.gen.go +++ b/internal/test/issues/issue-2232/issue2232.gen.go @@ -254,7 +254,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H ErrorHandlerFunc: options.ErrorHandlerFunc, } - m.HandleFunc("GET "+options.BaseURL+"/v1/endpoint", wrapper.GetEndpoint) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/v1/endpoint", wrapper.GetEndpoint) return m } diff --git a/internal/test/issues/issue-2238/issue2238.gen.go b/internal/test/issues/issue-2238/issue2238.gen.go index 81f395ddfa..043529ebce 100644 --- a/internal/test/issues/issue-2238/issue2238.gen.go +++ b/internal/test/issues/issue-2238/issue2238.gen.go @@ -128,7 +128,7 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err 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 } diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index 1686dac248..e49ab36cfe 100644 --- a/internal/test/issues/issue-312/issue.gen.go +++ b/internal/test/issues/issue-312/issue.gen.go @@ -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 } diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go index f024999d6a..2c57dd3223 100644 --- a/internal/test/issues/issue-52/issue.gen.go +++ b/internal/test/issues/issue-52/issue.gen.go @@ -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 } 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 99bfcd9548..ee161c40e9 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -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 } 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 0c29ab71eb..1da3d74579 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -173,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 } diff --git a/internal/test/issues/issue240/client.gen.go b/internal/test/issues/issue240/client.gen.go index 8a0a533589..2953b8ce4a 100644 --- a/internal/test/issues/issue240/client.gen.go +++ b/internal/test/issues/issue240/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 } diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index 068f8e6d4a..fa5b29bc16 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -1052,7 +1052,7 @@ func NewListEntitiesRequest(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 } @@ -1112,7 +1112,7 @@ func NewPostFooRequestWithBody(server string, params *PostFooParams, contentType queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("POST", queryURL.String(), body) + req, err := http.NewRequest(http.MethodPost, queryURL.String(), body) if err != nil { return nil, err } @@ -1141,7 +1141,7 @@ func NewListItemsRequest(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 } @@ -1179,7 +1179,7 @@ func NewCreateItemRequestWithBody(server string, contentType string, body io.Rea 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 } @@ -1241,7 +1241,7 @@ func NewCreateOrderRequestWithBody(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 } @@ -1270,7 +1270,7 @@ func NewGetOutcomeRequest(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 } @@ -1308,7 +1308,7 @@ func NewPostOutcomeRequestWithBody(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 } @@ -1348,7 +1348,7 @@ func NewSendPayloadRequestWithBody(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 } @@ -1388,7 +1388,7 @@ func NewCreatePetRequestWithBody(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 } @@ -1428,7 +1428,7 @@ func NewQueryRequestWithBody(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 } @@ -1457,7 +1457,7 @@ func NewGetQuxRequest(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 } @@ -1495,7 +1495,7 @@ func NewPostQuxRequestWithBody(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 } @@ -1524,7 +1524,7 @@ func NewGetRenamedSchemaRequest(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 } @@ -1562,7 +1562,7 @@ func NewPostRenamedSchemaRequestWithBody(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 } @@ -1631,7 +1631,7 @@ func NewPatchResourceRequestWithBody(server string, id string, contentType strin 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 } @@ -1660,7 +1660,7 @@ func NewGetStatusRequest(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 } @@ -1687,7 +1687,7 @@ func NewGetZapRequest(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 } @@ -1725,7 +1725,7 @@ func NewPostZapRequestWithBody(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 } 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 index 8d02762813..0b00613664 100644 --- 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 @@ -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 } @@ -498,7 +498,7 @@ 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 } 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 206ddbf64d..93dc41ff9b 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 @@ -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 } @@ -498,7 +498,7 @@ 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 } 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 6cf9d6e7fe..935b805c1c 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 @@ -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 } @@ -498,7 +498,7 @@ 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 } 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 e34d1c4663..50478990af 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 @@ -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 } @@ -498,7 +498,7 @@ 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 } 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 17f65ad9ee..59d306d519 100644 --- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go +++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go @@ -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 } @@ -498,7 +498,7 @@ 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 } diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 5821715fc2..6b68f2fd25 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -568,7 +568,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 } @@ -595,7 +595,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 } @@ -768,7 +768,7 @@ func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Reques queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) if err != nil { return nil, err } @@ -795,7 +795,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 } @@ -923,7 +923,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 } @@ -957,7 +957,7 @@ 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 } @@ -991,7 +991,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 } @@ -1025,7 +1025,7 @@ 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 } @@ -1059,7 +1059,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 } @@ -1093,7 +1093,7 @@ 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 } @@ -1127,7 +1127,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 } @@ -1161,7 +1161,7 @@ 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 } @@ -1192,7 +1192,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 } @@ -1237,7 +1237,7 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http. queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) if err != nil { return nil, err } @@ -1408,7 +1408,7 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), nil) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) if err != nil { return nil, err } @@ -1442,7 +1442,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 } @@ -1476,7 +1476,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 } @@ -1510,7 +1510,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 } @@ -1544,7 +1544,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 } @@ -1578,7 +1578,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 } @@ -1609,7 +1609,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 } diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index f8293f4608..ad4e412d05 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -399,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 } @@ -426,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 } @@ -453,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 } @@ -491,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 } @@ -527,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 } @@ -561,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 } @@ -588,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 } @@ -622,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 } @@ -678,7 +678,7 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s queryURL.RawQuery = queryValues.Encode() } - req, err := http.NewRequest("GET", queryURL.String(), body) + req, err := http.NewRequest(http.MethodGet, queryURL.String(), body) if err != nil { return nil, err } @@ -707,7 +707,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 } diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index fa66382d70..66eeb2014c 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -549,7 +549,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 } @@ -578,7 +578,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 } @@ -607,7 +607,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 } @@ -669,7 +669,7 @@ 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 } @@ -709,7 +709,7 @@ func NewRequiredJSONBodyRequestWithBody(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 } @@ -749,7 +749,7 @@ func NewRequiredTextBodyRequestWithBody(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 } @@ -785,7 +785,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 } @@ -823,7 +823,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 } @@ -863,7 +863,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 } @@ -892,7 +892,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 } @@ -921,7 +921,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 } @@ -961,7 +961,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 } @@ -1001,7 +1001,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 } @@ -1065,7 +1065,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 } diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index c4cf39d483..c27989b6c4 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -449,33 +449,33 @@ 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("POST") + r.HandleFunc(options.BaseURL+"/multipart", wrapper.MultipartExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods("POST") + r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods("POST") + r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods("POST") + r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods("GET") + r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods(http.MethodGet) - r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods("POST") + r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods("POST") + r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods(http.MethodPost) - r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods("POST") + r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods(http.MethodPost) return r } diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 99160f5f0b..271fcdccd4 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -457,20 +457,20 @@ 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("POST "+options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody) - m.HandleFunc("POST "+options.BaseURL+"/required-text-body", wrapper.RequiredTextBody) - 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+"/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 } diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 19c533f1e6..819c5c5158 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -323,6 +323,31 @@ func genServerURLWithVariablesFunctionParams(goTypePrefix string, variables map[ 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{ @@ -355,4 +380,5 @@ var TemplateFunctions = template.FuncMap{ "toGoComment": StringWithTypeNameToGoComment, "genServerURLWithVariablesFunctionParams": genServerURLWithVariablesFunctionParams, + "httpMethodConstant": httpMethodConstant, } diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index e172642825..d85ffb5631 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -235,7 +235,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr queryURL.RawQuery = queryValues.Encode() } {{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 } diff --git a/pkg/codegen/templates/gorilla/gorilla-register.tmpl b/pkg/codegen/templates/gorilla/gorilla-register.tmpl index b019e1dbbf..28e8ff2720 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.{{.OperationId}}).Methods({{.Method | httpMethodConstant}}) {{end}} return r } diff --git a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl index bed4685c74..2aa164ddfd 100644 --- a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl @@ -49,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.{{.OperationId}}) {{end}} return m } From 357f00c5149d41acf6f00ac157a957dca3d22457 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Tue, 24 Mar 2026 03:40:22 +0800 Subject: [PATCH 216/293] fix(cli): remove unused `initialism-overrides` option (#2287) * fix(cli): remove unused `initialism-overrides` option Signed-off-by: Gaiaz Iusipov * test: update `TestGenerateDefaultOperationID` Signed-off-by: Gaiaz Iusipov --------- Signed-off-by: Gaiaz Iusipov Co-authored-by: Marcin Romaszewicz --- cmd/oapi-codegen/oapi-codegen.go | 4 ---- configuration-schema.json | 4 ---- pkg/codegen/codegen.go | 2 +- pkg/codegen/configuration.go | 2 -- pkg/codegen/operations.go | 13 +++---------- pkg/codegen/operations_test.go | 2 +- 6 files changed, 5 insertions(+), 22 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 088821f5da..777697b7b8 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -58,7 +58,6 @@ var ( flagExcludeSchemas string flagResponseTypeSuffix string flagAliasTypes bool - flagInitialismOverrides bool ) type configuration struct { @@ -112,7 +111,6 @@ func main() { 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 if possible.") - flag.BoolVar(&flagInitialismOverrides, "initialism-overrides", false, "Use initialism overrides.") flag.Parse() @@ -459,8 +457,6 @@ func updateConfigFromFlags(cfg *configuration) error { cfg.OutputFile = flagOutputFile } - cfg.OutputOptions.InitialismOverrides = flagInitialismOverrides - return nil } diff --git a/configuration-schema.json b/configuration-schema.json index d25061e31b..ff325c1f6e 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -181,10 +181,6 @@ "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`", diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 6aedce1805..44cfc6faf2 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -229,7 +229,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) } diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 1db5deff02..d3e67a1b95 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -316,8 +316,6 @@ 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"` diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 5d9f735506..beffe95751 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -602,16 +602,9 @@ 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 } @@ -639,7 +632,7 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper operationId := op.OperationID // We rely on OperationID to generate function names, it's required if operationId == "" { - operationId, err = generateDefaultOperationID(opName, requestPath, toCamelCaseFunc) + operationId, err = generateDefaultOperationID(opName, requestPath) if err != nil { return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s", opName, requestPath, err) @@ -736,7 +729,7 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper return operations, nil } -func generateDefaultOperationID(opName string, requestPath string, toCamelCaseFunc func(string) string) (string, error) { +func generateDefaultOperationID(opName string, requestPath string) (string, error) { var operationId = strings.ToLower(opName) if opName == "" { diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go index 77a54a8c25..0eff03e2c2 100644 --- a/pkg/codegen/operations_test.go +++ b/pkg/codegen/operations_test.go @@ -131,7 +131,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) From ddd9e9093462dbc6c9338196e7b3ed178e3d8ab7 Mon Sep 17 00:00:00 2001 From: lestrrat <49281+lestrrat@users.noreply.github.com> Date: Tue, 24 Mar 2026 05:44:36 +0900 Subject: [PATCH 217/293] update jwx to v3 (#2300) --- .../authenticated-api/echo/server/fake_jws.go | 23 +++++++------ .../echo/server/jwt_authenticator.go | 19 +++++------ examples/authenticated-api/stdhttp/go.mod | 17 ++++++---- examples/authenticated-api/stdhttp/go.sum | 34 ++++++++++--------- .../stdhttp/server/fake_jws.go | 23 +++++++------ .../stdhttp/server/jwt_authenticator.go | 19 +++++------ examples/go.mod | 14 ++++---- examples/go.sum | 30 ++++++++-------- 8 files changed, 92 insertions(+), 87 deletions(-) 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 c9d9a73a5a..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" ) @@ -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/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index 456ea79cc6..f86436a306 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -6,7 +6,7 @@ replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( github.com/getkin/kin-openapi v0.134.0 - github.com/lestrrat-go/jwx v1.2.31 + github.com/lestrrat-go/jwx/v3 v3.0.13 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/testutil v1.1.0 @@ -22,25 +22,28 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/gorilla/mux v1.8.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/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/dsig v1.0.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.2 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/segmentio/asm v1.2.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/valyala/fastjson v1.6.7 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.46.0 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 190a8206db..0ad850b61a 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -53,19 +53,20 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/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.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= +github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +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.31 h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54= -github.com/lestrrat-go/jwx v1.2.31/go.mod h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c= -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.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0= +github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= +github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk= +github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU= +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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -95,11 +96,11 @@ 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= @@ -109,12 +110,13 @@ github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE 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.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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= +github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= @@ -123,8 +125,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec 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/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= 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 b29a67302c..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 @@ -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/go.mod b/examples/go.mod index 998f23e291..9894cd261e 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -13,7 +13,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/kataras/iris/v12 v12.2.11 github.com/labstack/echo/v4 v4.15.1 - github.com/lestrrat-go/jwx v1.2.31 + github.com/lestrrat-go/jwx/v3 v3.0.13 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 @@ -67,11 +67,12 @@ require ( github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/labstack/gommon v0.4.2 // 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.2 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/dsig v1.0.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.2 // 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.9.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -85,13 +86,13 @@ require ( github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.54.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect + github.com/segmentio/asm v1.2.1 // indirect github.com/sirupsen/logrus v1.9.1 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect @@ -101,6 +102,7 @@ require ( github.com/ugorji/go/codec v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/fastjson v1.6.7 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 49512be9b8..a30c9a83b6 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -153,19 +153,20 @@ 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/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.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= -github.com/lestrrat-go/blackmagic v1.0.2/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.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= +github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +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.31 h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54= -github.com/lestrrat-go/jwx v1.2.31/go.mod h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c= -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.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0= +github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= +github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk= +github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU= +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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= @@ -227,8 +228,6 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -245,6 +244,8 @@ github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQ github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= 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/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= @@ -262,7 +263,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -284,6 +284,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw 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/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= +github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= 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= From c322d1a39424a20b0a07f7e7190c45cede3775db Mon Sep 17 00:00:00 2001 From: TelpeNight Date: Thu, 26 Mar 2026 01:27:31 +0100 Subject: [PATCH 218/293] add tests for https://github.com/oapi-codegen/oapi-codegen/issues/2183 (#2184) * add tests for https://github.com/oapi-codegen/oapi-codegen/issues/2183 * fix(client): preserve literal commas in form/explode=false query params The generated client code was round-tripping styled query parameter fragments through url.ParseQuery + url.Values.Encode(), which re-encoded comma delimiters as %2C. Per the OpenAPI spec, form/explode=false arrays should use literal commas as delimiters (e.g. color=blue,black,brown). Change the client template to collect pre-encoded fragments from StyleParamWithLocation and join them directly, bypassing the re-encoding. Also moves the issue-2183 test to internal/test/issues/issue-2183/, extends it with explode=true and multi-param cases, and documents the remaining server-side limitation (oapi-codegen/runtime#91) for values containing embedded commas. Fixes #2183 Co-Authored-By: Claude Opus 4.6 * Regenerate affected boilerplate * Make sure to URL encode parameter names * Use non-deprecated runtime code * Update runtime and unstub test This exercises all the test cases in the bug. I will do a followup commit to fix all parameter handling. * Defer client parameter styling to runtime The split partial styling between client and runtime causes problems, so just have runtime do all of the work. --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 --- examples/generate/serverurls/gen.go | 1 + .../petstore-expanded/petstore-client.gen.go | 31 +++-- internal/test/any_of/param/param.gen.go | 27 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 +- .../issues/issue-2031/prefer/issue2031.gen.go | 19 +-- .../issues/issue-2183/communication_test.go | 116 ++++++++++++++++++ .../name_conflict_resolution.gen.go | 19 +-- internal/test/parameters/parameters.gen.go | 113 ++++++++--------- internal/test/schemas/schemas.gen.go | 19 +-- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 +- pkg/codegen/templates/client.tmpl | 21 ++-- 13 files changed, 250 insertions(+), 128 deletions(-) create mode 100644 internal/test/issues/issue-2183/communication_test.go diff --git a/examples/generate/serverurls/gen.go b/examples/generate/serverurls/gen.go index b32073b2cd..79eace7a7a 100644 --- a/examples/generate/serverurls/gen.go +++ b/examples/generate/serverurls/gen.go @@ -55,6 +55,7 @@ func NewServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServer u = strings.ReplaceAll(u, "{basePath}", string(basePath)) u = strings.ReplaceAll(u, "{noDefault}", string(noDefault)) + // TODO in the future, this will validate that the value is part of the ServerUrlTheProductionAPIServerPortVariable enum u = strings.ReplaceAll(u, "{port}", string(port)) u = strings.ReplaceAll(u, "{username}", string(username)) diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go index 9bd928f497..aa35c93ca6 100644 --- a/examples/petstore-expanded/petstore-client.gen.go +++ b/examples/petstore-expanded/petstore-client.gen.go @@ -226,41 +226,38 @@ 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 queryFragments, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil { return nil, err } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } + rawQueryFragments = append(rawQueryFragments, queryFragments) } } 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 queryFragments, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { return nil, err } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } + rawQueryFragments = append(rawQueryFragments, queryFragments) } } - 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) diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 2a082006cc..825bafeefd 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.StyleParamWithOptions("form", true, "test", *params.Test, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); 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) } } @@ -304,19 +306,18 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err if queryFrag, err := runtime.StyleParamWithOptions("form", true, "test2", *params.Test2, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); 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) } } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) diff --git a/internal/test/go.mod b/internal/test/go.mod index 3883c7548e..8f1d5e347a 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -15,7 +15,7 @@ require ( github.com/labstack/echo/v4 v4.15.1 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.2.0 + github.com/oapi-codegen/runtime v1.3.1 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 diff --git a/internal/test/go.sum b/internal/test/go.sum index e4e6e813f1..7153d67001 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -180,8 +180,8 @@ 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.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/runtime v1.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+5xB9g= +github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go index 2aeb2c4b88..2dcb3372d1 100644 --- a/internal/test/issues/issue-2031/prefer/issue2031.gen.go +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -128,25 +128,30 @@ 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.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 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) } } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) 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/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index fa5b29bc16..bc3fb1ba5a 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -1091,25 +1091,30 @@ func NewPostFooRequestWithBody(server string, params *PostFooParams, contentType } 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 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) } } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodPost, queryURL.String(), body) diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 6b68f2fd25..9a66132841 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -747,25 +747,30 @@ 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.StyleParamWithOptions("form", true, "enumPathParam", *params.EnumPathParam, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); 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) } } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) @@ -1220,21 +1225,26 @@ 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.StyleParamWithOptions("deepObject", true, "deepObj", params.DeepObj, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); 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) } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) @@ -1265,19 +1275,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.StyleParamWithOptions("form", true, "ea", *params.Ea, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); 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) } } @@ -1287,13 +1299,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if queryFrag, err := runtime.StyleParamWithOptions("form", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); 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) } } @@ -1303,13 +1311,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if queryFrag, err := runtime.StyleParamWithOptions("form", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); 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) } } @@ -1319,13 +1323,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if queryFrag, err := runtime.StyleParamWithOptions("form", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); 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) } } @@ -1335,13 +1335,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re 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 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) } } @@ -1351,13 +1347,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re 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 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) } } @@ -1367,13 +1359,9 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if queryFrag, err := runtime.StyleParamWithOptions("form", true, "ps", *params.Ps, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); 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) } } @@ -1393,19 +1381,18 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re if queryFrag, err := runtime.StyleParamWithOptions("form", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); 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) } } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index ad4e412d05..fe10c8c7eb 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -661,21 +661,26 @@ 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.StyleParamWithOptions("form", true, "foo", params.Foo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); 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) } } - queryURL.RawQuery = queryValues.Encode() + if encoded := queryValues.Encode(); encoded != "" { + rawQueryFragments = append(rawQueryFragments, encoded) + } + queryURL.RawQuery = strings.Join(rawQueryFragments, "&") } req, err := http.NewRequest(http.MethodGet, queryURL.String(), body) diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 443f10af94..18f7838442 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( github.com/getkin/kin-openapi v0.134.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.2.0 + github.com/oapi-codegen/runtime v1.3.1 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 5ba1c74b30..743c6649a8 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -61,8 +61,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/runtime v1.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+5xB9g= +github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index d85ffb5631..74407a3ebf 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -203,7 +203,13 @@ 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 .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}} {{if .IsPassThrough}} @@ -220,19 +226,18 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr {{if .IsStyled}} 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 .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 | httpMethodConstant}}, queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}}) From a3a04d4d994dea6a2f0c6ac1bab02cb2ca6a5d30 Mon Sep 17 00:00:00 2001 From: Joe Petrich Date: Fri, 27 Mar 2026 01:01:44 -0400 Subject: [PATCH 219/293] Support handler-specific middleware for gofiber (#2302) * feat(fiber): add per-handler middleware support (HandlerMiddlewares) (#2) Add Fiber per-handler middleware support * fix(test/issue518): add models:true to config so generated code compiles (#4) * chore(fiber): regenerate existing fiber server files with middleware chain support (#5) --------- Co-authored-by: Courty --- .../issue-1529/strict-fiber/issue1529.gen.go | 26 ++- internal/test/issues/issue1469/main.gen.go | 26 ++- internal/test/issues/issue518/config.yaml | 6 + internal/test/issues/issue518/doc.go | 3 + internal/test/issues/issue518/main.gen.go | 101 +++++++++ internal/test/issues/issue518/main_test.go | 88 ++++++++ internal/test/issues/issue518/spec.yaml | 21 ++ .../test/strict-server/fiber/server.gen.go | 208 ++++++++++++++++-- .../templates/fiber/fiber-handler.tmpl | 2 + .../templates/fiber/fiber-middleware.tmpl | 18 +- 10 files changed, 469 insertions(+), 30 deletions(-) create mode 100644 internal/test/issues/issue518/config.yaml create mode 100644 internal/test/issues/issue518/doc.go create mode 100644 internal/test/issues/issue518/main.gen.go create mode 100644 internal/test/issues/issue518/main_test.go create mode 100644 internal/test/issues/issue518/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 index f4fe591c04..62cd9ce025 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -268,21 +268,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. @@ -293,7 +308,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/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/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/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index 44d3c65de7..2ab5fc04b9 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -72,45 +72,119 @@ 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) } // RequiredJSONBody operation middleware func (siw *ServerInterfaceWrapper) RequiredJSONBody(c *fiber.Ctx) error { - return siw.Handler.RequiredJSONBody(c) + 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 { - return siw.Handler.RequiredTextBody(c) + 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 @@ -126,37 +200,109 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) err 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 @@ -206,19 +352,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. @@ -229,7 +400,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/pkg/codegen/templates/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl index 7745e0d88e..46aab9607d 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 { diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index dc48266696..5fcbe41383 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -1,9 +1,11 @@ // 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}} @@ -36,7 +38,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}} @@ -168,6 +170,18 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{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}} From e126f5a4d8015eecb3dda96d517ce2b243dc9921 Mon Sep 17 00:00:00 2001 From: Nicolas Mattelaer <113113091+nicolasmattelaer@users.noreply.github.com> Date: Fri, 3 Apr 2026 02:33:12 +0200 Subject: [PATCH 220/293] change FormParams to FormValues (#2311) Co-authored-by: nmattela --- pkg/codegen/templates/strict/strict-echo5.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/templates/strict/strict-echo5.tmpl b/pkg/codegen/templates/strict/strict-echo5.tmpl index 1f377bfdab..5afb443606 100644 --- a/pkg/codegen/templates/strict/strict-echo5.tmpl +++ b/pkg/codegen/templates/strict/strict-echo5.tmpl @@ -38,7 +38,7 @@ type strictHandler struct { } request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body {{else if eq .NameTag "Formdata" -}} - if form, err := ctx.FormParams(); err == nil { + if form, err := ctx.FormValues(); err == nil { var body {{$opid}}{{.NameTag}}RequestBody if err := runtime.BindForm(&body, form, nil, nil); err != nil { return err From 8822002562cd177574eeac49d084ba91dd37fea8 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Fri, 3 Apr 2026 08:42:22 +0800 Subject: [PATCH 221/293] style: simplify and modernize (#2305) * style: simplify and modernize Signed-off-by: Gaiaz Iusipov * revert: adding compile-time checks Signed-off-by: Gaiaz Iusipov --------- Signed-off-by: Gaiaz Iusipov Co-authored-by: Marcin Romaszewicz --- .../authenticated-api/stdhttp/api/api.gen.go | 4 +- .../minimal-server/stdhttp/api/ping.gen.go | 4 +- .../stdhttp/api/petstore.gen.go | 4 +- .../test/issues/issue-1963/issue1963.gen.go | 4 +- .../test/issues/issue-2190/issue2190.gen.go | 4 +- .../test/issues/issue-2232/issue2232.gen.go | 4 +- .../test/strict-server/stdhttp/server.gen.go | 4 +- pkg/codegen/codegen.go | 43 +++++++--------- pkg/codegen/gather.go | 43 +++++++++------- pkg/codegen/merge_schemas.go | 25 ++++----- pkg/codegen/merge_schemas_v1.go | 3 +- pkg/codegen/operations.go | 51 ++++++++----------- pkg/codegen/prune.go | 22 ++++---- pkg/codegen/resolve_names.go | 4 +- pkg/codegen/schema.go | 10 ++-- pkg/codegen/template_helpers.go | 10 ++-- .../templates/stdhttp/std-http-handler.tmpl | 4 +- pkg/codegen/typemapping.go | 18 +++---- pkg/codegen/utils.go | 46 +++++------------ 19 files changed, 136 insertions(+), 171 deletions(-) diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index da76ee17b2..b370659441 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -543,10 +543,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/examples/minimal-server/stdhttp/api/ping.gen.go b/examples/minimal-server/stdhttp/api/ping.gen.go index 0b1984332e..0d4ab7751a 100644 --- a/examples/minimal-server/stdhttp/api/ping.gen.go +++ b/examples/minimal-server/stdhttp/api/ping.gen.go @@ -119,10 +119,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index 1581d7705f..74019839df 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -259,10 +259,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/internal/test/issues/issue-1963/issue1963.gen.go b/internal/test/issues/issue-1963/issue1963.gen.go index 9c5b00bd9b..15164e4b62 100644 --- a/internal/test/issues/issue-1963/issue1963.gen.go +++ b/internal/test/issues/issue-1963/issue1963.gen.go @@ -220,10 +220,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/internal/test/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index d911a8474c..8cc8570388 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -345,10 +345,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/internal/test/issues/issue-2232/issue2232.gen.go b/internal/test/issues/issue-2232/issue2232.gen.go index 9b98648470..b99598ba4f 100644 --- a/internal/test/issues/issue-2232/issue2232.gen.go +++ b/internal/test/issues/issue-2232/issue2232.gen.go @@ -208,10 +208,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 271fcdccd4..8eca306a54 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -411,10 +411,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 44cfc6faf2..2d0ed9a0c1 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -24,9 +24,11 @@ import ( "go/scanner" "io" "io/fs" + "maps" "net/http" "os" "runtime/debug" + "slices" "sort" "strings" "text/template" @@ -103,11 +105,8 @@ func constructImportMapping(importMapping map[string]string) 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 := pathToImport[packagePath]; !ok && packagePath != importMappingCurrentPackage { @@ -255,7 +254,7 @@ 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 @@ -626,11 +625,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...) @@ -944,7 +939,7 @@ func resolvedNameForComponent(section, name string, contentType ...string) strin } if len(matches) > 0 { if len(matches) > 1 { - sort.Strings(matches) + slices.Sort(matches) } return globalState.resolvedNames[matches[0]] } @@ -1243,14 +1238,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 } @@ -1263,7 +1258,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) { if err != nil { return nil, err } - MergeImports(res, imprts) + maps.Copy(res, imprts) } } @@ -1272,7 +1267,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 { @@ -1281,7 +1276,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) { if err != nil { return nil, err } - MergeImports(res, imprts) + maps.Copy(res, imprts) } } @@ -1316,7 +1311,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 } @@ -1343,14 +1338,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 @@ -1371,7 +1366,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 } @@ -1389,7 +1384,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 @@ -1408,7 +1403,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 @@ -1424,7 +1419,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/gather.go b/pkg/codegen/gather.go index 84bd7e55df..0daf2ccf74 100644 --- a/pkg/codegen/gather.go +++ b/pkg/codegen/gather.go @@ -1,14 +1,18 @@ package codegen import ( + "cmp" "fmt" - "sort" + "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 @@ -18,6 +22,8 @@ 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 @@ -82,13 +88,13 @@ func (sc SchemaContext) Suffix() string { // 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 + 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 @@ -105,11 +111,13 @@ func GatherSchemas(spec *openapi3.T, opts Configuration) []*GatheredSchema { var schemas []*GatheredSchema if spec.Components != nil { - schemas = append(schemas, gatherComponentSchemas(spec.Components)...) - schemas = append(schemas, gatherComponentParameters(spec.Components)...) - schemas = append(schemas, gatherComponentResponses(spec.Components)...) - schemas = append(schemas, gatherComponentRequestBodies(spec.Components)...) - schemas = append(schemas, gatherComponentHeaders(spec.Components)...) + 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 @@ -268,10 +276,8 @@ func gatherComponentHeaders(components *openapi3.Components) []*GatheredSchema { // `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 { - var result []*GatheredSchema - if spec.Paths == nil { - return result + return nil } // Collect all operations sorted for determinism @@ -296,10 +302,11 @@ func gatherClientResponseWrappers(spec *openapi3.T) []*GatheredSchema { } // Sort by operationID for determinism - sort.Slice(ops, func(i, j int) bool { - return ops[i].op.OperationID < ops[j].op.OperationID + 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"}, diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index a2c979aa19..b9286703b3 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -3,6 +3,7 @@ package codegen import ( "errors" "fmt" + "maps" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -87,14 +88,10 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) { func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) { var result openapi3.Schema - result.Extensions = make(map[string]any) - 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...) @@ -195,14 +192,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() 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/operations.go b/pkg/codegen/operations.go index beffe95751..436c46d178 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" @@ -180,7 +182,7 @@ func (pd ParameterDefinition) IndirectOptional() bool { // 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 == false && pd.Schema.SkipOptionalPointer == false //nolint:staticcheck + return !pd.Required && !pd.Schema.SkipOptionalPointer } type ParameterDefinitions []ParameterDefinition @@ -198,7 +200,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 @@ -373,21 +375,21 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini switch { // HAL+JSON: - case StringInArray(contentTypeName, contentTypesHalJSON): + case slices.Contains(contentTypesHalJSON, contentTypeName): typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName)) case contentTypeName == "application/json": // if it's the standard application/json typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName)) // 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") // YAML: - case StringInArray(contentTypeName, contentTypesYAML): + case slices.Contains(contentTypesYAML, contentTypeName): typeName = fmt.Sprintf("YAML%s", nameNormalizer(responseName)) // XML: - case StringInArray(contentTypeName, contentTypesXML): + case slices.Contains(contentTypesXML, contentTypeName): typeName = fmt.Sprintf("XML%s", nameNormalizer(responseName)) default: continue @@ -424,13 +426,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 @@ -730,23 +729,21 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { } func generateDefaultOperationID(opName string, requestPath string) (string, error) { - var operationId = strings.ToLower(opName) - 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 @@ -835,7 +832,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 @@ -844,8 +841,8 @@ 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 } @@ -991,13 +988,9 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { // Parameter-level extensions take precedence over schema-level ones. extensions := make(map[string]any) if param.Spec.Schema != nil && param.Spec.Schema.Value != nil { - for k, v := range param.Spec.Schema.Value.Extensions { - extensions[k] = v - } - } - for k, v := range param.Spec.Extensions { - extensions[k] = v + maps.Copy(extensions, param.Spec.Schema.Value.Extensions) } + maps.Copy(extensions, param.Spec.Extensions) prop := Property{ Description: param.Spec.Description, JsonFieldName: param.ParamName, diff --git a/pkg/codegen/prune.go b/pkg/codegen/prune.go index e97ba3469e..efdac65f0b 100644 --- a/pkg/codegen/prune.go +++ b/pkg/codegen/prune.go @@ -7,10 +7,6 @@ import ( "github.com/getkin/kin-openapi/openapi3" ) -func stringInSlice(a string, list []string) bool { - return slices.Contains(list, a) -} - type RefWrapper struct { Ref string HasValue bool @@ -398,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) } @@ -406,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) } @@ -417,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) // } @@ -425,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) } @@ -433,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) } @@ -441,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) } @@ -449,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) } @@ -457,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) } @@ -465,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 index f6d65f5b92..1695d67f35 100644 --- a/pkg/codegen/resolve_names.go +++ b/pkg/codegen/resolve_names.go @@ -113,7 +113,7 @@ func resolveCollisions(names []*ResolvedName) { const maxIterations = 20 for _, strategy := range strategies { - for iter := 0; iter < maxIterations; iter++ { + for range maxIterations { groups := groupByName(names) anyCollision := false anyProgress := false @@ -261,7 +261,7 @@ func tryStatusCodeSuffix(group []*ResolvedName) bool { // Returns true if any name was modified, false if no progress was made. func tryParamIndexSuffix(group []*ResolvedName) bool { hasMultipleParams := false - for i := 0; i < len(group); i++ { + for i := range group { for j := i + 1; j < len(group); j++ { if group[i].Schema.ParamIndex != group[j].Schema.ParamIndex { hasMultipleParams = true diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 799e327dea..167b6c627a 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -3,6 +3,7 @@ package codegen import ( "errors" "fmt" + "slices" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -39,7 +40,6 @@ type Schema struct { // The original OpenAPIv3 Schema. OAPISchema *openapi3.Schema - } // IsPrimitive returns true if the schema represents a primitive OpenAPI type @@ -149,7 +149,7 @@ func (p Property) RequiresNilCheck() bool { // 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 == false && p.Schema.SkipOptionalPointer == false //nolint:staticcheck + return !p.Required && !p.Schema.SkipOptionalPointer } // ZeroValueIsNil is a helper function to determine if the given Go type used for this property @@ -269,7 +269,7 @@ func (u UnionElement) String() string { // Method generate union method name for template functions `As/From/Merge`. func (u UnionElement) Method() string { var method strings.Builder - for _, part := range strings.Split(string(u), `.`) { + for part := range strings.SplitSeq(string(u), `.`) { method.WriteString(UppercaseFirstCharacter(part)) } return method.String() @@ -440,7 +440,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, @@ -631,7 +631,7 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem 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) diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 819c5c5158..3ea88718bb 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -17,6 +17,7 @@ import ( "bytes" "fmt" "os" + "slices" "strings" "text/template" @@ -24,6 +25,7 @@ import ( "golang.org/x/text/language" "github.com/getkin/kin-openapi/openapi3" + "github.com/oapi-codegen/oapi-codegen/v2/pkg/util" ) @@ -147,7 +149,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++ } } @@ -164,7 +166,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"+ @@ -184,7 +186,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"+ @@ -198,7 +200,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"+ diff --git a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl index 2aa164ddfd..59434aaef4 100644 --- a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl @@ -3,10 +3,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { diff --git a/pkg/codegen/typemapping.go b/pkg/codegen/typemapping.go index f5e20b54ac..2a54695f68 100644 --- a/pkg/codegen/typemapping.go +++ b/pkg/codegen/typemapping.go @@ -1,5 +1,7 @@ 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 { @@ -16,10 +18,10 @@ type FormatMapping struct { // TypeMapping defines the mapping from OpenAPI types to Go types. type TypeMapping struct { - Integer FormatMapping `yaml:"integer,omitempty" json:"integer,omitempty"` - Number FormatMapping `yaml:"number,omitempty" json:"number,omitempty"` - Boolean FormatMapping `yaml:"boolean,omitempty" json:"boolean,omitempty"` - String FormatMapping `yaml:"string,omitempty" json:"string,omitempty"` + 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. @@ -39,9 +41,7 @@ func (base FormatMapping) merge(user FormatMapping) FormatMapping { } // Copy base formats - for k, v := range base.Formats { - result.Formats[k] = v - } + maps.Copy(result.Formats, base.Formats) // Override with user default if specified if user.Default.Type != "" { @@ -49,9 +49,7 @@ func (base FormatMapping) merge(user FormatMapping) FormatMapping { } // Override/add user formats - for k, v := range user.Formats { - result.Formats[k] = v - } + maps.Copy(result.Formats, user.Formats) return result } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index b6fb91985f..fb921b58a2 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -15,13 +15,14 @@ package codegen import ( "bytes" + "cmp" "fmt" "go/token" + "maps" "net/url" "reflect" "regexp" "slices" - "sort" "strconv" "strings" "unicode" @@ -82,7 +83,7 @@ func (m NameNormalizerMap) Options() []string { options = append(options, string(key)) } - sort.Strings(options) + slices.Sort(options) return options } @@ -350,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 } @@ -372,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 } @@ -405,24 +406,13 @@ func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) { return 0, false } -// SortedParameterKeys returns sorted keys for a SecuritySchemeRef dict +// SortedSecuritySchemeKeys returns sorted keys for a SecuritySchemeRef dict func SortedSecuritySchemeKeys(dict map[string]*openapi3.SecuritySchemeRef) []string { - keys := make([]string, len(dict)) - i := 0 - for key := range dict { - keys[i] = key - i++ - } - sort.Strings(keys) + keys := slices.Collect(maps.Keys(dict)) + slices.Sort(keys) return keys } -// StringInArray checks whether the specified string is present in an array -// of strings -func StringInArray(str string, array []string) bool { - return slices.Contains(array, str) -} - // RefPathToObjName returns the name of referenced object without changes. // // #/components/schemas/Foo -> Foo @@ -1122,12 +1112,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. @@ -1144,9 +1128,5 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool { return false } - return *s.AdditionalProperties.Has == false //nolint:staticcheck -} - -func sliceContains[E comparable](s []E, v E) bool { - return slices.Contains(s, v) + return !*s.AdditionalProperties.Has } From af135a92c7de0a98eedf9c916f4c618f8598d950 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 04:21:15 +0000 Subject: [PATCH 222/293] chore(deps): update release-drafter/release-drafter action to v7 (.github/workflows) (#2293) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Marcin Romaszewicz --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 36d0c96320..17a281c8cb 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@00ce30b0ce8a4d67bccfca59421cdf6c55dd0784 # v6.3.0 + - uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7.1.1 with: name: next tag: next From a76544bd16ff78abe4bde9c9c682e1ef22e3a12d Mon Sep 17 00:00:00 2001 From: yoshiikipom Date: Sat, 4 Apr 2026 08:54:58 +0900 Subject: [PATCH 223/293] fix: avoid stack overflow errors when using heavily recursive types (#1377) As noted in #1373, we have cases where a heavily recursive `allOf` could lead to a stack overflow error. To avoid this, we can track the references that we've seen, and not recurse further if we have already traversed that ref. Closes #1373. Co-authored-by: Jamie Tanna --- internal/test/issues/issue-1373/config.yaml | 4 +++ internal/test/issues/issue-1373/generate.go | 3 ++ internal/test/issues/issue-1373/issue.gen.go | 15 +++++++++ internal/test/issues/issue-1373/spec.yaml | 32 ++++++++++++++++++++ pkg/codegen/merge_schemas.go | 23 ++++++++++---- pkg/codegen/merge_schemas_test.go | 12 ++++---- 6 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 internal/test/issues/issue-1373/config.yaml create mode 100644 internal/test/issues/issue-1373/generate.go create mode 100644 internal/test/issues/issue-1373/issue.gen.go create mode 100644 internal/test/issues/issue-1373/spec.yaml 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/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index b9286703b3..b9d3af778a 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -38,7 +38,12 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { if err != nil { return Schema{}, err } - schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true) + + seenSchemaRef := make(map[string]bool) + if allOf[i].Ref != "" { + seenSchemaRef[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) } @@ -71,11 +76,17 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) { return schema, nil } -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 + } + schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true, seenSchemaRef) if err != nil { return openapi3.Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err) } @@ -85,7 +96,7 @@ 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]any, len(s1.Extensions)+len(s2.Extensions)) @@ -100,7 +111,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") } @@ -108,7 +119,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") } diff --git a/pkg/codegen/merge_schemas_test.go b/pkg/codegen/merge_schemas_test.go index 9ba9a9f166..61fcbef125 100644 --- a/pkg/codegen/merge_schemas_test.go +++ b/pkg/codegen/merge_schemas_test.go @@ -17,7 +17,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{Discriminator: disc} s2 := openapi3.Schema{} - result, err := mergeOpenapiSchemas(s1, s2, true) + result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool)) require.NoError(t, err) assert.Equal(t, disc, result.Discriminator) }) @@ -26,7 +26,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{} s2 := openapi3.Schema{Discriminator: disc} - result, err := mergeOpenapiSchemas(s1, s2, true) + result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool)) require.NoError(t, err) assert.Equal(t, disc, result.Discriminator) }) @@ -36,7 +36,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{Discriminator: disc} s2 := openapi3.Schema{Discriminator: disc2} - _, err := mergeOpenapiSchemas(s1, s2, true) + _, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool)) require.Error(t, err) assert.Contains(t, err.Error(), "discriminators") }) @@ -45,7 +45,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{} s2 := openapi3.Schema{} - result, err := mergeOpenapiSchemas(s1, s2, true) + result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool)) require.NoError(t, err) assert.Nil(t, result.Discriminator) }) @@ -54,7 +54,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{Discriminator: disc} s2 := openapi3.Schema{} - _, err := mergeOpenapiSchemas(s1, s2, false) + _, err := mergeOpenapiSchemas(s1, s2, false, make(map[string]bool)) require.Error(t, err) }) @@ -62,7 +62,7 @@ func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) { s1 := openapi3.Schema{} s2 := openapi3.Schema{Discriminator: disc} - _, err := mergeOpenapiSchemas(s1, s2, false) + _, err := mergeOpenapiSchemas(s1, s2, false, make(map[string]bool)) require.Error(t, err) }) } From 9ea3cc79a4c7c7863729bcc80485a1580797c90a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 3 Apr 2026 17:49:43 -0700 Subject: [PATCH 224/293] Update release-drafter config for V7 (#2317) We no longer need to explicitly inherit release drafter settings from the org, and the V6 syntax no longer works, so I'm deleting the file. --- .github/release-drafter.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 852c651a59..0000000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1 +0,0 @@ -_extends: oapi-codegen/.github From 9aeaed3ce77629f295d845743a584d951f7a3c44 Mon Sep 17 00:00:00 2001 From: David Pollack Date: Wed, 8 Apr 2026 19:03:52 +0200 Subject: [PATCH 225/293] fix: add x-go-name for server urls (#2304) * fix: add x-go-name for server urls * Update pkg/codegen/server_urls.go do not swallow the extGoName error from automated review bot Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- examples/generate/serverurls/api.yaml | 4 ++++ examples/generate/serverurls/gen.go | 10 ++++++++++ examples/generate/serverurls/gen_test.go | 6 ++++++ pkg/codegen/server_urls.go | 22 +++++++++++++++++----- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/examples/generate/serverurls/api.yaml b/examples/generate/serverurls/api.yaml index 48695165ba..ec7c73a5e2 100644 --- a/examples/generate/serverurls/api.yaml +++ b/examples/generate/serverurls/api.yaml @@ -45,3 +45,7 @@ servers: 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/gen.go b/examples/generate/serverurls/gen.go index 79eace7a7a..b7d3485430 100644 --- a/examples/generate/serverurls/gen.go +++ b/examples/generate/serverurls/gen.go @@ -8,19 +8,29 @@ import ( "strings" ) +// MyCustomAPIServer defines the Server URL for Custom named server +const MyCustomAPIServer = "https://api.example.com/v2" + // 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:80" // 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:80" // 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 diff --git a/examples/generate/serverurls/gen_test.go b/examples/generate/serverurls/gen_test.go index 2a2ecfb41a..573fb5f2e5 100644 --- a/examples/generate/serverurls/gen_test.go +++ b/examples/generate/serverurls/gen_test.go @@ -46,3 +46,9 @@ func TestServerUrlTheProductionAPIServer(t *testing.T) { assert.Equal(t, "https://demo.gigantic-server.com:8443/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) + }) +} diff --git a/pkg/codegen/server_urls.go b/pkg/codegen/server_urls.go index d10c2d9f60..48ef564d26 100644 --- a/pkg/codegen/server_urls.go +++ b/pkg/codegen/server_urls.go @@ -24,12 +24,24 @@ func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) names := make(map[string]*openapi3.Server) for _, server := range spec.Servers { - suffix := server.Description - if suffix == "" { - suffix = nameNormalizer(server.URL) + var name string + if goNameExt, ok := server.Extensions[extGoName]; ok { + customName, err := extParseGoFieldName(goNameExt) + if err != nil { + return "", 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) } - name := serverURLPrefix + UppercaseFirstCharacter(suffix) - name = nameNormalizer(name) // if this is the only type with this name, store it if _, conflict := names[name]; !conflict { From 9fffadedd3a520b20bd57cc2ece3fcfcb8d4bd9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:39:38 -0700 Subject: [PATCH 226/293] fix(deps): update module github.com/getkin/kin-openapi to v0.135.0 (go.mod) (#2320) * fix(deps): update module github.com/getkin/kin-openapi to v0.135.0 (go.mod) * Tidy modules after kin update --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Marcin Romaszewicz --- examples/authenticated-api/stdhttp/go.mod | 6 +++--- examples/authenticated-api/stdhttp/go.sum | 12 ++++++------ examples/go.mod | 6 +++--- examples/go.sum | 12 ++++++------ examples/minimal-server/stdhttp/go.mod | 6 +++--- examples/minimal-server/stdhttp/go.sum | 12 ++++++------ examples/petstore-expanded/echo-v5/go.mod | 6 +++--- examples/petstore-expanded/echo-v5/go.sum | 12 ++++++------ examples/petstore-expanded/stdhttp/go.mod | 6 +++--- examples/petstore-expanded/stdhttp/go.sum | 12 ++++++------ go.mod | 6 +++--- go.sum | 12 ++++++------ internal/test/go.mod | 6 +++--- internal/test/go.sum | 12 ++++++------ internal/test/strict-server/stdhttp/go.mod | 6 +++--- internal/test/strict-server/stdhttp/go.sum | 12 ++++++------ 16 files changed, 72 insertions(+), 72 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index f86436a306..fb23f089c8 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 github.com/lestrrat-go/jwx/v3 v3.0.13 github.com/oapi-codegen/nethttp-middleware v1.1.2 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 @@ -30,8 +30,8 @@ require ( github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/segmentio/asm v1.2.1 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index 0ad850b61a..cc925ce715 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -78,10 +78,10 @@ github.com/oapi-codegen/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/examples/go.mod b/examples/go.mod index 9894cd261e..2f91e1b6f1 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 github.com/gin-gonic/gin v1.11.0 github.com/go-chi/chi/v5 v5.2.5 github.com/gofiber/fiber/v2 v2.52.12 @@ -82,8 +82,8 @@ require ( 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/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/examples/go.sum b/examples/go.sum index a30c9a83b6..2b6bcbf2a5 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -50,8 +50,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= @@ -208,10 +208,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index acb4ea2c04..71f2290349 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -8,14 +8,14 @@ require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-0000000000 require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.134.0 // indirect + github.com/getkin/kin-openapi v0.135.0 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index f2ff34e742..f76bbdc4b8 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -11,8 +11,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -54,10 +54,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod index 09e9022013..b3a8f20752 100644 --- a/examples/petstore-expanded/echo-v5/go.mod +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -5,7 +5,7 @@ go 1.25.0 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 github.com/labstack/echo/v5 v5.0.4 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 github.com/oapi-codegen/runtime v1.2.0 @@ -24,8 +24,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum index 15fb93d7b0..dabb4bcc08 100644 --- a/examples/petstore-expanded/echo-v5/go.sum +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -69,10 +69,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 481ce10be2..57f32bba62 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 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.2.0 @@ -24,8 +24,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 9976dfce36..9878819024 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -69,10 +69,10 @@ github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+Lpmz github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/go.mod b/go.mod index d6c392af11..795c4bb8a3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.3 toolchain go1.24.4 require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 github.com/speakeasy-api/openapi-overlay v0.10.2 github.com/stretchr/testify v1.11.1 golang.org/x/mod v0.33.0 @@ -23,8 +23,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/go.sum b/go.sum index c7599ec79b..84f94478e9 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -54,10 +54,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 8f1d5e347a..394eba4890 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.24.3 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.134.0 + github.com/getkin/kin-openapi v0.135.0 github.com/gin-gonic/gin v1.11.0 github.com/go-chi/chi/v5 v5.2.5 github.com/gofiber/fiber/v2 v2.52.12 @@ -70,8 +70,8 @@ require ( 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/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index 7153d67001..7c43e209da 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -48,8 +48,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= @@ -184,10 +184,10 @@ github.com/oapi-codegen/runtime v1.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+ github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 18f7838442..d034f0a0f1 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -7,7 +7,7 @@ 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.134.0 + github.com/getkin/kin-openapi v0.135.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.3.1 @@ -25,8 +25,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c // indirect - github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 743c6649a8..40349bbd97 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -15,8 +15,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU= -github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE= +github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= @@ -65,10 +65,10 @@ github.com/oapi-codegen/runtime v1.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+ github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= 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.0.0-20260313112342-a3ea61cb4d4c h1:7ACFcSaQsrWtrH4WHHfUqE1C+f8r2uv8KGaW0jTNjus= -github.com/oasdiff/yaml v0.0.0-20260313112342-a3ea61cb4d4c/go.mod h1:JKox4Gszkxt57kj27u7rvi7IFoIULvCZHUsBTUmQM/s= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b h1:vivRhVUAa9t1q0Db4ZmezBP8pWQWnXHFokZj0AOea2g= -github.com/oasdiff/yaml3 v0.0.0-20260224194419-61cd415a242b/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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= From 20bf6e117bf1ee4fbdcb5189ea1b3e0c0ef6c8f5 Mon Sep 17 00:00:00 2001 From: netixx Date: Thu, 9 Apr 2026 19:59:58 +0200 Subject: [PATCH 227/293] fix(deps): use updated import path for `github.com/speakeasy-api/openapi/overlay` (#2231) * Fix import path for overlay pkg * Update code and go.sum for overlay package The new overlay package has a small API change and we need to re-run go mod tidy on everything after rebasing. --------- Co-authored-by: Francois Espinet Co-authored-by: Marcin Romaszewicz --- examples/authenticated-api/stdhttp/go.mod | 4 ++-- examples/authenticated-api/stdhttp/go.sum | 19 ++++++++++++------- examples/go.mod | 4 ++-- examples/go.sum | 19 ++++++++++++------- examples/minimal-server/stdhttp/go.mod | 4 ++-- examples/minimal-server/stdhttp/go.sum | 19 ++++++++++++------- examples/petstore-expanded/echo-v5/go.mod | 4 ++-- examples/petstore-expanded/echo-v5/go.sum | 19 ++++++++++++------- examples/petstore-expanded/stdhttp/go.mod | 4 ++-- examples/petstore-expanded/stdhttp/go.sum | 19 ++++++++++++------- go.mod | 4 ++-- go.sum | 19 ++++++++++++------- internal/test/go.mod | 4 ++-- internal/test/go.sum | 19 ++++++++++++------- internal/test/strict-server/stdhttp/go.mod | 4 ++-- internal/test/strict-server/stdhttp/go.sum | 19 ++++++++++++------- pkg/util/loader.go | 4 ++-- 17 files changed, 114 insertions(+), 74 deletions(-) diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index fb23f089c8..d78e8862e0 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -35,8 +35,8 @@ require ( github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/segmentio/asm v1.2.1 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/valyala/fastjson v1.6.7 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum index cc925ce715..de52d10215 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -48,11 +48,13 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= @@ -99,14 +101,16 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -186,8 +190,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/examples/go.mod b/examples/go.mod index 2f91e1b6f1..bb3606ee88 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -94,8 +94,8 @@ require ( github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/sirupsen/logrus v1.9.1 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/tdewolff/minify/v2 v2.20.19 // indirect github.com/tdewolff/parse/v2 v2.7.12 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect diff --git a/examples/go.sum b/examples/go.sum index 2b6bcbf2a5..290007b754 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -144,9 +144,12 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/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/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= @@ -188,7 +191,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -238,6 +240,8 @@ github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQ 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.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= @@ -251,10 +255,10 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -402,8 +406,9 @@ google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7I google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 71f2290349..362bef5c56 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -17,8 +17,8 @@ require ( github.com/oasdiff/yaml v0.0.9 // indirect github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect golang.org/x/mod v0.33.0 // indirect diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum index f76bbdc4b8..bb4e53d852 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -42,11 +42,13 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -75,12 +77,14 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -155,8 +159,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod index b3a8f20752..6e9281b491 100644 --- a/examples/petstore-expanded/echo-v5/go.mod +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -28,8 +28,8 @@ require ( github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect golang.org/x/mod v0.33.0 // indirect diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum index dabb4bcc08..824267217c 100644 --- a/examples/petstore-expanded/echo-v5/go.sum +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -51,11 +51,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v5 v5.0.4 h1:ll3I/O8BifjMztj9dD1vx/peZQv8cR2CTUdQK6QxGGc= github.com/labstack/echo/v5 v5.0.4/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= @@ -90,12 +92,14 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -174,8 +178,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 57f32bba62..ed943eb926 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -28,8 +28,8 @@ require ( github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect golang.org/x/mod v0.33.0 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index 9878819024..a3cede0861 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -51,11 +51,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -90,12 +92,14 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -172,8 +176,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/go.mod b/go.mod index 795c4bb8a3..4d5e7aff80 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.4 require ( github.com/getkin/kin-openapi v0.135.0 - github.com/speakeasy-api/openapi-overlay v0.10.2 + github.com/speakeasy-api/openapi v1.19.2 github.com/stretchr/testify v1.11.1 golang.org/x/mod v0.33.0 golang.org/x/text v0.34.0 @@ -27,7 +27,7 @@ require ( github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect diff --git a/go.sum b/go.sum index 84f94478e9..bb4e53d852 100644 --- a/go.sum +++ b/go.sum @@ -42,11 +42,13 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -75,12 +77,14 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU= -github.com/speakeasy-api/openapi-overlay v0.10.2/go.mod h1:n0iOU7AqKpNFfEt6tq7qYITC4f0yzVVdFw0S7hukemg= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -155,8 +159,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 394eba4890..c7ead48dc0 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -81,8 +81,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect github.com/sirupsen/logrus v1.9.1 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tdewolff/minify/v2 v2.20.19 // indirect github.com/tdewolff/parse/v2 v2.7.12 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index 7c43e209da..2a53255d80 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -142,9 +142,12 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/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/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= @@ -172,7 +175,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -213,6 +215,8 @@ github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQB github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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= @@ -224,10 +228,10 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -371,8 +375,9 @@ google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7I google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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 h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= 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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index d034f0a0f1..3a14704185 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -29,8 +29,8 @@ require ( github.com/oasdiff/yaml3 v0.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.0 // indirect - github.com/speakeasy-api/openapi-overlay v0.10.3 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect golang.org/x/mod v0.33.0 // indirect diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index 40349bbd97..dc75c1b597 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -49,11 +49,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: 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.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -86,12 +88,14 @@ github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0V github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8= -github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= -github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= -github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= 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= @@ -168,8 +172,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 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= diff --git a/pkg/util/loader.go b/pkg/util/loader.go index 7eea07b156..3a3264e832 100644 --- a/pkg/util/loader.go +++ b/pkg/util/loader.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/getkin/kin-openapi/openapi3" - "github.com/speakeasy-api/openapi-overlay/pkg/loader" + "github.com/speakeasy-api/openapi/overlay/loader" "gopkg.in/yaml.v3" ) @@ -74,7 +74,7 @@ func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (s } if opts.Strict { - err, vs := overlay.ApplyToStrict(&node) + 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- ")) } From cd4f5aa19861ac52f11cc1409eae4cab17aafc7b Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 11 Apr 2026 13:25:27 -0700 Subject: [PATCH 228/293] fix: allOf cycle detection oversight (#2316) PR #1377 was merged too early. This is a small follow-up tweak to make sure that #1373 is fixed properly. seed allOf[0] ref into cycle detection to prevent stack overflow when self-ref is first When the self-referencing $ref appears at position 0 in allOf, its ref was never added to seenSchemaRef. If s1's own AllOf contained a back-reference to itself, mergeAllOf would not detect the cycle. Seed allOf[0].Ref into a top-level seen set that is copied into each iteration's seenSchemaRef map, closing this gap. Co-authored-by: Claude Opus 4.6 (1M context) --- pkg/codegen/merge_schemas.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index b9d3af778a..1b21ae3e22 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -32,6 +32,13 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { 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]) @@ -40,8 +47,12 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { } 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 { From 9107bfb7db47990e964e053bdd1f77196b80740a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 11 Apr 2026 13:26:06 -0700 Subject: [PATCH 229/293] Add support for path aliases (#2312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support for path aliases Closes #223 When an OpenAPI spec uses $ref to alias one path to another (e.g. /test2: $ref: '#/paths/~1test'), kin-openapi inlines the referenced path item into both entries. Previously this produced duplicate ServerInterface methods, wrapper functions, and type definitions — generating Go code that never compiled. Detect internal path aliases via PathItem.Ref (only when it starts with "#/paths/", to distinguish from external file references). For alias operations: - Server: skip interface method, wrapper, and strict handler generation. Route registration still emits both paths, pointing to the canonical wrapper via the new HandlerName() method on OperationDefinition. - Client: generate methods with a suffixed OperationId (e.g. GetTestAlias0) so each aliased path gets its own request builder targeting the correct URL. Co-Authored-By: Claude Opus 4.6 (1M context) * fix: skip operationId write-back for alias operations Alias paths share the same *openapi3.Operation pointer as the canonical path. Writing the suffixed alias name (e.g. GetTestAlias0) back to op.OperationID would corrupt the canonical operation's ID in the embedded spec. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- internal/test/pathalias/client-config.yaml | 5 + internal/test/pathalias/client.gen.go | 336 ++++++++++++++++++ internal/test/pathalias/doc.go | 4 + internal/test/pathalias/server-config.yaml | 6 + internal/test/pathalias/server.gen.go | 179 ++++++++++ internal/test/pathalias/spec.yaml | 28 ++ pkg/codegen/operations.go | 39 +- pkg/codegen/templates/chi/chi-handler.tmpl | 2 +- pkg/codegen/templates/chi/chi-interface.tmpl | 8 +- pkg/codegen/templates/chi/chi-middleware.tmpl | 4 +- .../templates/echo/echo-interface.tmpl | 4 +- pkg/codegen/templates/echo/echo-register.tmpl | 2 +- pkg/codegen/templates/echo/echo-wrappers.tmpl | 4 +- .../templates/echo/v5/echo-interface.tmpl | 4 +- .../templates/echo/v5/echo-register.tmpl | 2 +- .../templates/echo/v5/echo-wrappers.tmpl | 4 +- .../templates/fiber/fiber-handler.tmpl | 2 +- .../templates/fiber/fiber-interface.tmpl | 4 +- .../templates/fiber/fiber-middleware.tmpl | 4 +- pkg/codegen/templates/gin/gin-interface.tmpl | 4 +- pkg/codegen/templates/gin/gin-register.tmpl | 2 +- pkg/codegen/templates/gin/gin-wrappers.tmpl | 4 +- .../templates/gorilla/gorilla-interface.tmpl | 4 +- .../templates/gorilla/gorilla-middleware.tmpl | 4 +- .../templates/gorilla/gorilla-register.tmpl | 2 +- pkg/codegen/templates/iris/iris-handler.tmpl | 2 +- .../templates/iris/iris-interface.tmpl | 4 +- .../templates/iris/iris-middleware.tmpl | 4 +- .../templates/stdhttp/std-http-handler.tmpl | 2 +- .../templates/stdhttp/std-http-interface.tmpl | 4 +- .../stdhttp/std-http-middleware.tmpl | 4 +- pkg/codegen/templates/strict/strict-echo.tmpl | 2 + .../templates/strict/strict-echo5.tmpl | 2 + .../strict/strict-fiber-interface.tmpl | 8 +- .../templates/strict/strict-fiber.tmpl | 2 + pkg/codegen/templates/strict/strict-gin.tmpl | 2 + pkg/codegen/templates/strict/strict-http.tmpl | 2 + .../templates/strict/strict-interface.tmpl | 8 +- .../strict/strict-iris-interface.tmpl | 8 +- pkg/codegen/templates/strict/strict-iris.tmpl | 2 + 40 files changed, 661 insertions(+), 56 deletions(-) create mode 100644 internal/test/pathalias/client-config.yaml create mode 100644 internal/test/pathalias/client.gen.go create mode 100644 internal/test/pathalias/doc.go create mode 100644 internal/test/pathalias/server-config.yaml create mode 100644 internal/test/pathalias/server.gen.go create mode 100644 internal/test/pathalias/spec.yaml 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..d1ee30f777 --- /dev/null +++ b/internal/test/pathalias/client.gen.go @@ -0,0 +1,336 @@ +// 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 +} + +// 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 +} + +type GetTestAlias0Response struct { + Body []byte + HTTPResponse *http.Response + JSON200 *B +} + +// 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 +} + +// 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/pkg/codegen/operations.go b/pkg/codegen/operations.go index 436c46d178..d9bf1dcbfb 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -270,6 +270,18 @@ 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) +} + +// 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 } // Params returns the list of all parameters except Path parameters. Path parameters @@ -608,6 +620,10 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { return operations, nil } + // 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 @@ -641,8 +657,25 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { } operationId = typeNamePrefix(operationId) + operationId - if !globalState.options.Compatibility.PreserveOriginalOperationIdCasingInEmbeddedSpec { - // update the existing, shared, copy of the spec if we're not wanting to preserve it + // 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 } @@ -699,6 +732,8 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { Bodies: bodyDefinitions, Responses: responseDefinitions, TypeDefinitions: typeDefinitions, + IsAlias: isAlias, + AliasTarget: aliasTarget, } // check for overrides of SecurityDefinitions. 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 c3e7cf82ae..347b1dd95d 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -8,7 +8,7 @@ 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) }} @@ -194,7 +194,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/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..dcfeb54f18 100644 --- a/pkg/codegen/templates/echo/echo-register.tmpl +++ b/pkg/codegen/templates/echo/echo-register.tmpl @@ -28,6 +28,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL Handler: si, } {{end}} -{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) +{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}) {{end}} } diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index a086d75d4e..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}}" ------------- @@ -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 index 1531eef866..6d5b874bed 100644 --- a/pkg/codegen/templates/echo/v5/echo-interface.tmpl +++ b/pkg/codegen/templates/echo/v5/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/v5/echo-register.tmpl b/pkg/codegen/templates/echo/v5/echo-register.tmpl index 78de21b83e..bd0e968b0f 100644 --- a/pkg/codegen/templates/echo/v5/echo-register.tmpl +++ b/pkg/codegen/templates/echo/v5/echo-register.tmpl @@ -28,6 +28,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL Handler: si, } {{end}} -{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}}) +{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}) {{end}} } diff --git a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl index 9f7d608dda..c061240df3 100644 --- a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/v5/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}}" ------------- @@ -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/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl index 46aab9607d..5ac8be929f 100644 --- a/pkg/codegen/templates/fiber/fiber-handler.tmpl +++ b/pkg/codegen/templates/fiber/fiber-handler.tmpl @@ -22,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 5fcbe41383..002d144101 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -8,7 +8,7 @@ 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 { @@ -184,4 +184,4 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { 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 e18c0d644c..872590fa7a 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -8,7 +8,7 @@ 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) { @@ -183,4 +183,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 6a1b18ce2d..1624a7ed6a 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -8,7 +8,7 @@ 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) }} @@ -194,7 +194,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 28e8ff2720..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 | httpMethodConstant}}) +r.HandleFunc(options.BaseURL+"{{.Path | swaggerUriToGorillaUri }}", wrapper.{{.HandlerName}}).Methods({{.Method | httpMethodConstant}}) {{end}} return r } 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 7ee4ce9b2b..2a6cfaa769 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -5,7 +5,7 @@ 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 @@ -158,4 +158,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/stdhttp/std-http-handler.tmpl b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl index 59434aaef4..63fccd2445 100644 --- a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl @@ -49,7 +49,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H ErrorHandlerFunc: options.ErrorHandlerFunc, } {{end}} -{{range .}}m.HandleFunc({{.Method | httpMethodConstant}}+" "+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 fbccc40a03..daadd981a7 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -8,7 +8,7 @@ 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) }} @@ -194,7 +194,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 7b470c8ce7..f8b523fa91 100644 --- a/pkg/codegen/templates/strict/strict-echo.tmpl +++ b/pkg/codegen/templates/strict/strict-echo.tmpl @@ -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 @@ -107,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 index 5afb443606..1073714599 100644 --- a/pkg/codegen/templates/strict/strict-echo5.tmpl +++ b/pkg/codegen/templates/strict/strict-echo5.tmpl @@ -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 @@ -94,4 +95,5 @@ type strictHandler struct { } 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 e83f7e38aa..11d1cbaad0 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 -}} @@ -133,13 +133,13 @@ } {{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 59a2c0736b..106f33a766 100644 --- a/pkg/codegen/templates/strict/strict-fiber.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber.tmpl @@ -13,6 +13,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 @@ -100,4 +101,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 40a7b7bcb1..86040d6d76 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -12,6 +12,7 @@ type strictHandler struct { {{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 @@ -118,4 +119,5 @@ type strictHandler struct { ctx.Error(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 7314c26fd7..d55341ca0b 100644 --- a/pkg/codegen/templates/strict/strict-http.tmpl +++ b/pkg/codegen/templates/strict/strict-http.tmpl @@ -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 @@ -132,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 ab56514e8a..f6108de7a9 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 -}} @@ -151,13 +151,13 @@ } {{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 95b78d0645..aa7e166d9f 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 -}} @@ -135,13 +135,13 @@ } {{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 6ed301574c..804efb0cf3 100644 --- a/pkg/codegen/templates/strict/strict-iris.tmpl +++ b/pkg/codegen/templates/strict/strict-iris.tmpl @@ -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 @@ -118,4 +119,5 @@ type strictHandler struct { return } } + {{end}} {{end}} From a4c36dc26466d4d96dd985900a87101efd8ba66c Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 11 Apr 2026 13:31:26 -0700 Subject: [PATCH 230/293] support optional/nullable response headers (#2301) * support optional/nullable response headers Closes: #2267 Response headers in strict server code were always generated as direct value types regardless of whether they were required. This adds support for optional and nullable response headers in the strict-interface and strict-responses templates. Add Required and Nullable fields to ResponseHeaderDefinition, populated from the OpenAPI header object. Add GoTypeDef(), IsOptional(), and IsNullable() methods that mirror the existing Property logic for determining whether a field should be a pointer, nullable.Nullable[T], or a direct value. Update strict-interface.tmpl and strict-responses.tmpl to use GoTypeDef for struct field types, and to conditionally guard w.Header().Set() calls with nil/IsSpecified checks for optional/nullable headers. Note: this is a breaking change for specs where response headers lack explicit `required: true`, since the OpenAPI default is false. Existing headers will change from direct values to pointers. This may need to be gated behind a config option. Co-Authored-By: Claude Opus 4.6 (1M context) * Add HeadersImplicitlyRequired compatibility flag for #2267 Allows users to restore the pre-v2.5.0 behavior where all response headers are treated as required, ignoring the OpenAPI `required` field. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- configuration-schema.json | 4 ++ internal/test/issues/issue-1676/ping.gen.go | 6 ++- .../issue.gen.go | 2 +- internal/test/strict-server/chi/server.gen.go | 51 +++++++++++-------- .../test/strict-server/echo/server.gen.go | 51 +++++++++++-------- .../test/strict-server/fiber/server.gen.go | 47 +++++++++-------- internal/test/strict-server/gin/server.gen.go | 51 +++++++++++-------- .../test/strict-server/gorilla/server.gen.go | 51 +++++++++++-------- .../test/strict-server/iris/server.gen.go | 47 +++++++++-------- .../test/strict-server/stdhttp/server.gen.go | 51 +++++++++++-------- .../test/strict-server/strict-schema.yaml | 14 +++++ pkg/codegen/configuration.go | 10 ++++ pkg/codegen/operations.go | 49 ++++++++++++++++-- .../templates/strict/strict-interface.tmpl | 38 ++++++++++++-- .../templates/strict/strict-responses.tmpl | 2 +- 15 files changed, 315 insertions(+), 159 deletions(-) diff --git a/configuration-schema.json b/configuration-schema.json index ff325c1f6e..21bfb0c0d5 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -115,6 +115,10 @@ "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" } } }, diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go index 53fa480501..395033a2ba 100644 --- a/internal/test/issues/issue-1676/ping.gen.go +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -168,7 +168,7 @@ type GetPingResponseObject interface { } type GetPing200ResponseHeaders struct { - MyHeader string + MyHeader *string } type GetPing200TextResponse struct { @@ -179,7 +179,9 @@ type GetPing200TextResponse struct { func (response GetPing200TextResponse) VisitGetPingResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "text/plain") - w.Header().Set("MyHeader", fmt.Sprint(response.Headers.MyHeader)) + if response.Headers.MyHeader != nil { + w.Header().Set("MyHeader", fmt.Sprint(*response.Headers.MyHeader)) + } w.WriteHeader(200) _, err := w.Write([]byte(response.Body)) 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/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 01ef76a0c7..3632359f84 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -1103,8 +1103,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -1121,6 +1123,12 @@ func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http w.Header().Set("Content-Type", "application/json") w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + if response.Headers.NullableHeader != nil { + w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader)) + } + if response.Headers.OptionalHeader != nil { + w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err @@ -1775,25 +1783,26 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 9770f43472..067448ae36 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -825,8 +825,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -843,6 +845,12 @@ func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http w.Header().Set("Content-Type", "application/json") w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + if response.Headers.NullableHeader != nil { + w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader)) + } + if response.Headers.OptionalHeader != nil { + w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err @@ -1450,25 +1458,26 @@ func (sh *strictHandler) UnionExample(ctx echo.Context) error { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index 2ab5fc04b9..c1b3bd431c 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -942,8 +942,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader string + OptionalHeader string } type HeadersExample200JSONResponse struct { @@ -954,6 +956,8 @@ 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)) + ctx.Response().Header.Set("nullable-header", fmt.Sprint(response.Headers.NullableHeader)) + ctx.Response().Header.Set("optional-header", fmt.Sprint(response.Headers.OptionalHeader)) ctx.Response().Header.Set("Content-Type", "application/json") ctx.Status(200) @@ -1557,25 +1561,26 @@ func (sh *strictHandler) UnionExample(ctx *fiber.Ctx) error { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 25b3f654db..d854ee3cc7 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -898,8 +898,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -916,6 +918,12 @@ func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http w.Header().Set("Content-Type", "application/json") w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + if response.Headers.NullableHeader != nil { + w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader)) + } + if response.Headers.OptionalHeader != nil { + w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err @@ -1573,25 +1581,26 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index c27989b6c4..48846b2438 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -1014,8 +1014,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -1032,6 +1034,12 @@ func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http w.Header().Set("Content-Type", "application/json") w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + if response.Headers.NullableHeader != nil { + w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader)) + } + if response.Headers.OptionalHeader != nil { + w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err @@ -1686,25 +1694,26 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 033e1dd769..7d81a25fe5 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -777,8 +777,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader string + OptionalHeader string } type HeadersExample200JSONResponse struct { @@ -789,6 +791,8 @@ 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)) + ctx.ResponseWriter().Header().Set("nullable-header", fmt.Sprint(response.Headers.NullableHeader)) + ctx.ResponseWriter().Header().Set("optional-header", fmt.Sprint(response.Headers.OptionalHeader)) ctx.ResponseWriter().Header().Set("Content-Type", "application/json") ctx.StatusCode(200) @@ -1459,25 +1463,26 @@ func (sh *strictHandler) UnionExample(ctx iris.Context) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 8eca306a54..21e96956c5 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -1009,8 +1009,10 @@ type HeadersExampleResponseObject interface { } type HeadersExample200ResponseHeaders struct { - Header1 string - Header2 int + Header1 string + Header2 int + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -1027,6 +1029,12 @@ func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http w.Header().Set("Content-Type", "application/json") w.Header().Set("header1", fmt.Sprint(response.Headers.Header1)) w.Header().Set("header2", fmt.Sprint(response.Headers.Header2)) + if response.Headers.NullableHeader != nil { + w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader)) + } + if response.Headers.OptionalHeader != nil { + w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err @@ -1681,25 +1689,26 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZTXPbNhP+Kzt431NKmrbjE2+NJ5O2aeuObJ86PkDESkJCAiiwFK3R6L93QEBfFq1K", - "qT4ynt5Ecr/wPLuLBTRlha6MVqjIsXzKLDqjlcP2oc+Fxb9qdOSfBLrCSkNSK5azD1z04rdZwizWjvdL", - "nKt7+UIrQtWqcmNKWXCvmn1xXn/KXDHCivtf/7c4YDn7X7YMJQtfXYbPvDIlstlslryI4O4zS9gIuUDb", - "Rht+Xq3bpolBljNHVqoh80aC2HWnmFSEQ7TemxeNQXiBeRz5lBmrDVqSAaMxL2vs9hTf6P4XLCisQKqB", - "3sTyViviUjkQcjBAi4ogggfehgNXG6MtoYD+BLyHgsChHaNlCSNJPjB2v/oeYsCOJWyM1gVHVxeXF5ee", - "L21QcSNZzt63rxJmOI3aBS0IMrqL91/u734H6YDXpCtOsuBlOYGKWzfiJQqQirQPsS7IXbDWk22J/1lE", - "7Y8RSp81bQJ90GJyjIRp83Ilna8vL0+Ul7OE3QRnXTYWQWUrBdaaGfC67MD8UX1VulGA1mobV5ZVdUnS", - "cEurXK2j/dtcZBfIF/aygbZVKjjxI6F+KE/nBj61WHJCsQMBvSC5Hw8r5o/Kwr/xc1YOYj/u7FP3I904", - "GOkGSINAXkIjaQRzxRcNVirg4KQalgjzoJJOMkuM296PSvTiWh68jaP3s2TNynPaNE3aFlBtS1SFFt9G", - "YcJkxYeYGTVcV/e2ObGc9SfkU3ZzgztQISeM8JkyU3Kptu/eJ2rp/yF9sMIO5eofpUWRekbSfqyP7sKN", - "5QVeyg8ac90EnIZKOl+l4aMb6boUwMuGT1zoD5sTRy+q+8mjLcyjjx3BgffJcrI1vu0xZEGtz6zzUPuA", - "z/SP1O6R+PvSd+qa2p+i9kwg0qFOv+Kk0VakhlteIaF12dTHOfO2hthh8o+FJBRcQR9B8QoF8AGhhU8a", - "oknXwU/w+0l/DiJLU+2BY/GQ/zllHrz2EMIS5h2wPOD3ko5kC8BPx6VqjmY46qZrrl5L+Cgyh87iwPmB", - "pIvjDvyCp96KxHmOTNtzc+Pwf4qk9ky+Pnj7lrDLsH3AweN77wJ1ePk6ZlFrF9i+cY7ZAcWxFKizytzs", - "aflsoDqDhRxIFGlcRRpie60l3GpVWKT1A4jfDJUmWBiD/gRohBAQaPfHBqGqHYHhzoGktouUMtwVCdxo", - "Ho/LyG6Dp4dlO93G6rsjcfruXIzeXF7tr/L+yHmzdpB4pR57v34MMvvemB3sxLLneetwfs9Uzo2kUbpy", - "pdxdwj8FgeWeXqAc+4lICbBItVUoYCz5/Bp0ozajgSWtXbNQCGM5Dc2vt/cZiJKttq5Zsu0K/OkNX9Ae", - "84+DU+VpreS2i/pH/xniDP1yb5BafafX8LwktIqTHOMPh7m/2bSiFd4N2kp7wXKyo4ent5dVs4SFf45C", - "C6pt6fsEkcmzLPzjdOEaPhyivZA640Z6FP4OAAD//0nTejA+HAAA", + "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", + "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", + "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", + "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", + "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", + "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", + "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", + "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", + "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", + "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", + "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", + "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", + "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", + "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", + "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", + "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", + "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", + "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", + "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", + "AAD//ysZ4qQMHQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index 8b18edd541..ba1a2ffab3 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: @@ -320,9 +330,11 @@ paths: description: OK headers: header1: + required: true schema: type: string header2: + required: true schema: type: integer content: @@ -346,9 +358,11 @@ components: description: OK headers: header1: + required: true schema: type: string header2: + required: true schema: type: integer content: diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index d3e67a1b95..abdab8f049 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -287,6 +287,16 @@ type CompatibilityOptions struct { // 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 { diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index d9bf1dcbfb..69f8fd9765 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -595,9 +595,43 @@ func (r ResponseContentDefinition) IsJSON() bool { } 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 @@ -940,7 +974,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) } diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index f6108de7a9..fc1f53ca01 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -32,7 +32,7 @@ {{if (and $hasHeaders (not $isRef)) -}} type {{$opid}}{{$statusCode}}ResponseHeaders struct { {{range .Headers -}} - {{.GoName}} {{.Schema.TypeDecl}} + {{.GoName}} {{.GoTypeDef}} {{end -}} } {{end}} @@ -83,7 +83,17 @@ } w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}}) {{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}}) _, err := buf.WriteTo(w) @@ -95,7 +105,17 @@ } w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}}) {{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}}) _, err = w.Write([]byte(form.Encode())) @@ -108,7 +128,17 @@ } {{end -}} {{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}}) diff --git a/pkg/codegen/templates/strict/strict-responses.tmpl b/pkg/codegen/templates/strict/strict-responses.tmpl index d04cbd7d6c..74f5d96494 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 -}} From 434cc16b427dcc1d63fc3e7e6b9c2f5337418be1 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Thu, 16 Apr 2026 15:36:27 +0100 Subject: [PATCH 231/293] docs: remove non-breaking spaces (#2328) Although they're safe in this case, Renovate's "hidden whitespace" detection is flagging it. As we don't need them, we can remove them. Not-signed-off-by: Jamie Tanna --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aa4dc860ee..bc9b8757e7 100644 --- a/README.md +++ b/README.md @@ -2134,11 +2134,11 @@ To get `oapi-codegen`'s multi-package support working, we need to set up our dir ``` ├── admin -│   ├── cfg.yaml -│   └── generate.go +│ ├── cfg.yaml +│ └── generate.go └── common ├── cfg.yaml -    └── generate.go + └── generate.go ``` We could start with our configuration file for our admin API spec: From c2095464aea566dafda7ff63b66b0f7e4fb51b42 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 20 Apr 2026 06:44:08 -0700 Subject: [PATCH 232/293] fix: clean up and test parameter binding (#2307) * fix: clean up and test parameter binding Audit and fix parameter binding in all 8 server code generation templates (Echo v4, Echo v5, Chi, Gin, Gorilla, Iris, Fiber, stdhttp) to ensure consistent, correct handling of path, query, header, and cookie parameters across all OpenAPI styles and types. Template fixes: - Add missing ParamLocation to path params (Gin, Fiber, Gorilla) and cookie params (Chi, Gin, Fiber, Gorilla, stdhttp) so the runtime applies correct URL escaping per location - Add missing Type/Format fields to Echo v5 path, header, and cookie params, and upgrade its query binding to BindQueryParameterWithOptions - Fix required deepObject query params rejected by a spurious pre-check in Chi, Gin, Gorilla, Fiber, and stdhttp templates - Fix Gin, Iris, and Fiber using query param getters instead of path param getters for content-based (passthrough/JSON) path parameters - Fix Iris cookie params calling nonexistent ctx.Cookie() (now ctx.GetCookie()) and query params calling ctx.QueryParam() (now ctx.URLParam()) - Fix Fiber cookie params redeclaring var in a loop (now block-scoped) - Fix Fiber not URL-decoding path param values for passthrough/JSON - Add _ = err to suppress unused variable when only passthrough path params exist (Chi, Gin, Gorilla, Iris, Fiber, stdhttp) Multi-router parameter roundtrip test: - New test infrastructure under internal/test/parameters/ with per-router subdirectories (echo, chi, gin, gorilla, iris, fiber, stdhttp) plus a shared client package - Each router's server echoes received parameters back as JSON; the shared testImpl sends requests via the generated client and verifies the JSON response matches the original values - Generated files isolated in gen/ subdirectories so go generate works even when generated code has compilation errors - Echo v5 in its own module (Go 1.25+) with version-guarded Makefile - Covers all OpenAPI parameter styles (simple, label, matrix, form, deepObject) x types (primitive, array, object) x explode flags across path, query, header, and cookie locations Skipped tests pending external changes: - spaceDelimited and pipeDelimited query styles: runtime does not yet support binding these styles (oapi-codegen/runtime#116) - stdhttp roundtrip: stdlib ServeMux cannot register path wildcards starting with a digit like {1param} (#2306) Closes: #777, #1752 Obsoletes: #1751, #2062 Co-Authored-By: Claude Opus 4.6 (1M context) * Update runtime and unstub tests Runtime 1.4.0 allows us to run almost all parameter tests. * Update all sub-modules runtime version * run go mod tidy in echo v5 --------- Co-authored-by: Claude Opus 4.6 (1M context) --- examples/go.mod | 2 +- examples/go.sum | 4 +- .../echo-v5/api/petstore-server.gen.go | 8 +- examples/petstore-expanded/echo-v5/go.mod | 4 +- examples/petstore-expanded/echo-v5/go.sum | 8 +- .../stdhttp/api/petstore.gen.go | 18 +- examples/petstore-expanded/stdhttp/go.mod | 4 +- examples/petstore-expanded/stdhttp/go.sum | 8 +- internal/test/cookies/cookies.gen.go | 5 +- internal/test/go.mod | 2 +- internal/test/go.sum | 4 +- .../issue-1378/bionicle/bionicle.gen.go | 3 +- .../issue-1378/fooservice/fooservice.gen.go | 3 +- .../test/issues/issue-2232/issue2232.gen.go | 37 +- .../name_normalizer.gen.go | 3 +- .../name_normalizer.gen.go | 3 +- .../name_normalizer.gen.go | 3 +- .../to-camel-case/name_normalizer.gen.go | 3 +- .../unset/name_normalizer.gen.go | 3 +- .../test/parameters/chi/gen/server.gen.go | 1663 +++++++++ internal/test/parameters/chi/gen/types.gen.go | 143 + internal/test/parameters/chi/server.cfg.yaml | 6 + internal/test/parameters/chi/server.go | 48 + internal/test/parameters/chi/types.cfg.yaml | 5 + .../test/parameters/client/client.cfg.yaml | 6 + internal/test/parameters/client/client.go | 3 + .../gen/client.gen.go} | 1477 ++++---- internal/test/parameters/config.yaml | 8 - internal/test/parameters/doc.go | 3 +- .../test/parameters/echo/gen/server.gen.go | 977 +++++ .../test/parameters/echo/gen/types.gen.go | 143 + .../parameters/{ => echo}/parameters_test.go | 341 +- internal/test/parameters/echo/server.cfg.yaml | 6 + internal/test/parameters/echo/server.go | 44 + internal/test/parameters/echo/types.cfg.yaml | 5 + internal/test/parameters/echov5/Makefile | 45 + .../test/parameters/echov5/client.cfg.yaml | 5 + internal/test/parameters/echov5/client.gen.go | 3162 +++++++++++++++++ .../parameters/echov5/echov5_param_test.go | 381 ++ internal/test/parameters/echov5/go.mod | 41 + internal/test/parameters/echov5/go.sum | 190 + .../test/parameters/echov5/server.cfg.yaml | 6 + internal/test/parameters/echov5/server.gen.go | 977 +++++ internal/test/parameters/echov5/server.go | 41 + .../test/parameters/echov5/types.cfg.yaml | 5 + internal/test/parameters/echov5/types.gen.go | 143 + .../test/parameters/fiber/gen/server.gen.go | 1430 ++++++++ .../test/parameters/fiber/gen/types.gen.go | 143 + .../test/parameters/fiber/server.cfg.yaml | 6 + internal/test/parameters/fiber/server.go | 44 + internal/test/parameters/fiber/types.cfg.yaml | 5 + .../test/parameters/gin/gen/server.gen.go | 1293 +++++++ internal/test/parameters/gin/gen/types.gen.go | 143 + internal/test/parameters/gin/server.cfg.yaml | 6 + internal/test/parameters/gin/server.go | 44 + internal/test/parameters/gin/types.cfg.yaml | 5 + .../test/parameters/gorilla/gen/server.gen.go | 1496 ++++++++ .../test/parameters/gorilla/gen/types.gen.go | 143 + .../test/parameters/gorilla/server.cfg.yaml | 6 + internal/test/parameters/gorilla/server.go | 48 + .../test/parameters/gorilla/types.cfg.yaml | 5 + .../test/parameters/iris/gen/server.gen.go | 1132 ++++++ .../test/parameters/iris/gen/types.gen.go | 143 + internal/test/parameters/iris/server.cfg.yaml | 6 + internal/test/parameters/iris/server.go | 44 + internal/test/parameters/iris/types.cfg.yaml | 5 + .../test/parameters/param_roundtrip_test.go | 517 +++ internal/test/parameters/parameters.yaml | 104 + .../test/parameters/stdhttp/gen/server.gen.go | 1478 ++++++++ .../test/parameters/stdhttp/gen/types.gen.go | 143 + .../test/parameters/stdhttp/server.cfg.yaml | 6 + internal/test/parameters/stdhttp/server.go | 48 + .../test/parameters/stdhttp/types.cfg.yaml | 5 + internal/test/server/server.gen.go | 35 +- internal/test/strict-server/chi/server.gen.go | 2 + .../test/strict-server/fiber/server.gen.go | 4 +- internal/test/strict-server/gin/server.gen.go | 4 +- .../test/strict-server/gorilla/server.gen.go | 4 +- .../test/strict-server/iris/server.gen.go | 2 + internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 4 +- .../test/strict-server/stdhttp/server.gen.go | 2 + pkg/codegen/templates/chi/chi-middleware.tmpl | 12 +- .../templates/echo/v5/echo-wrappers.tmpl | 8 +- .../templates/fiber/fiber-middleware.tmpl | 30 +- pkg/codegen/templates/gin/gin-wrappers.tmpl | 11 +- .../templates/gorilla/gorilla-middleware.tmpl | 14 +- .../templates/iris/iris-middleware.tmpl | 15 +- .../stdhttp/std-http-middleware.tmpl | 12 +- 89 files changed, 17426 insertions(+), 1182 deletions(-) create mode 100644 internal/test/parameters/chi/gen/server.gen.go create mode 100644 internal/test/parameters/chi/gen/types.gen.go create mode 100644 internal/test/parameters/chi/server.cfg.yaml create mode 100644 internal/test/parameters/chi/server.go create mode 100644 internal/test/parameters/chi/types.cfg.yaml create mode 100644 internal/test/parameters/client/client.cfg.yaml create mode 100644 internal/test/parameters/client/client.go rename internal/test/parameters/{parameters.gen.go => client/gen/client.gen.go} (69%) delete mode 100644 internal/test/parameters/config.yaml create mode 100644 internal/test/parameters/echo/gen/server.gen.go create mode 100644 internal/test/parameters/echo/gen/types.gen.go rename internal/test/parameters/{ => echo}/parameters_test.go (71%) create mode 100644 internal/test/parameters/echo/server.cfg.yaml create mode 100644 internal/test/parameters/echo/server.go create mode 100644 internal/test/parameters/echo/types.cfg.yaml create mode 100644 internal/test/parameters/echov5/Makefile create mode 100644 internal/test/parameters/echov5/client.cfg.yaml create mode 100644 internal/test/parameters/echov5/client.gen.go create mode 100644 internal/test/parameters/echov5/echov5_param_test.go create mode 100644 internal/test/parameters/echov5/go.mod create mode 100644 internal/test/parameters/echov5/go.sum create mode 100644 internal/test/parameters/echov5/server.cfg.yaml create mode 100644 internal/test/parameters/echov5/server.gen.go create mode 100644 internal/test/parameters/echov5/server.go create mode 100644 internal/test/parameters/echov5/types.cfg.yaml create mode 100644 internal/test/parameters/echov5/types.gen.go create mode 100644 internal/test/parameters/fiber/gen/server.gen.go create mode 100644 internal/test/parameters/fiber/gen/types.gen.go create mode 100644 internal/test/parameters/fiber/server.cfg.yaml create mode 100644 internal/test/parameters/fiber/server.go create mode 100644 internal/test/parameters/fiber/types.cfg.yaml create mode 100644 internal/test/parameters/gin/gen/server.gen.go create mode 100644 internal/test/parameters/gin/gen/types.gen.go create mode 100644 internal/test/parameters/gin/server.cfg.yaml create mode 100644 internal/test/parameters/gin/server.go create mode 100644 internal/test/parameters/gin/types.cfg.yaml create mode 100644 internal/test/parameters/gorilla/gen/server.gen.go create mode 100644 internal/test/parameters/gorilla/gen/types.gen.go create mode 100644 internal/test/parameters/gorilla/server.cfg.yaml create mode 100644 internal/test/parameters/gorilla/server.go create mode 100644 internal/test/parameters/gorilla/types.cfg.yaml create mode 100644 internal/test/parameters/iris/gen/server.gen.go create mode 100644 internal/test/parameters/iris/gen/types.gen.go create mode 100644 internal/test/parameters/iris/server.cfg.yaml create mode 100644 internal/test/parameters/iris/server.go create mode 100644 internal/test/parameters/iris/types.cfg.yaml create mode 100644 internal/test/parameters/param_roundtrip_test.go create mode 100644 internal/test/parameters/stdhttp/gen/server.gen.go create mode 100644 internal/test/parameters/stdhttp/gen/types.gen.go create mode 100644 internal/test/parameters/stdhttp/server.cfg.yaml create mode 100644 internal/test/parameters/stdhttp/server.go create mode 100644 internal/test/parameters/stdhttp/types.cfg.yaml diff --git a/examples/go.mod b/examples/go.mod index bb3606ee88..f0833793ce 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -20,7 +20,7 @@ require ( github.com/oapi-codegen/iris-middleware v1.0.5 github.com/oapi-codegen/nethttp-middleware v1.1.2 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.2.0 + github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 golang.org/x/lint v0.0.0-20241112194109-818c5a804067 diff --git a/examples/go.sum b/examples/go.sum index 290007b754..5777a31fe3 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -206,8 +206,8 @@ github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq github.com/oapi-codegen/iris-middleware v1.0.5/go.mod h1:/ysgvbjWyhfDAouIeUOjzIv+zsXfaIXlAQrsOU9/Kyo= github.com/oapi-codegen/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA= github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= -github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go index c99d14e424..ac4b6f5270 100644 --- a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go +++ b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go @@ -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)) } diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod index 6e9281b491..3a9a5d3ef9 100644 --- a/examples/petstore-expanded/echo-v5/go.mod +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -8,7 +8,7 @@ require ( github.com/getkin/kin-openapi v0.135.0 github.com/labstack/echo/v5 v5.0.4 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.2.0 + github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) @@ -19,7 +19,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum index 824267217c..a653a1f09f 100644 --- a/examples/petstore-expanded/echo-v5/go.sum +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -42,8 +42,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -67,8 +67,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index 74019839df..aa60a0891e 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -9,6 +9,7 @@ import ( "bytes" "compress/gzip" "encoding/base64" + "errors" "fmt" "net/http" "net/url" @@ -90,6 +91,7 @@ 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 @@ -98,7 +100,12 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque 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 } @@ -106,7 +113,12 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque 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,6 +151,7 @@ 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 @@ -164,6 +177,7 @@ 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 diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index ed943eb926..0a642f935f 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -8,7 +8,7 @@ require ( github.com/getkin/kin-openapi v0.135.0 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.2.0 + github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) @@ -19,7 +19,7 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum index a3cede0861..b5ae3a9f9f 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -42,8 +42,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -67,8 +67,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= -github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= +github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/internal/test/cookies/cookies.gen.go b/internal/test/cookies/cookies.gen.go index 4e9b6139ec..1efbec0cdf 100644 --- a/internal/test/cookies/cookies.gen.go +++ b/internal/test/cookies/cookies.gen.go @@ -49,6 +49,7 @@ type MiddlewareFunc func(http.Handler) http.Handler 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 @@ -58,7 +59,7 @@ func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.R if cookie, err = r.Cookie("authId"); err == nil { var value string - err = runtime.BindStyledParameterWithOptions("simple", "authId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false, Type: "string", Format: ""}) + 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 @@ -73,7 +74,7 @@ func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.R if cookie, err = r.Cookie("serverId"); err == nil { var value string - err = runtime.BindStyledParameterWithOptions("simple", "serverId", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: true, Required: false, Type: "string", Format: ""}) + 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 diff --git a/internal/test/go.mod b/internal/test/go.mod index c7ead48dc0..88b0357176 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -15,7 +15,7 @@ require ( github.com/labstack/echo/v4 v4.15.1 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.3.1 + github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 diff --git a/internal/test/go.sum b/internal/test/go.sum index 2a53255d80..969bd3f82f 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -182,8 +182,8 @@ 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.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+5xB9g= -github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= +github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index c18418eaef..ad3c48fb16 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -50,11 +50,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, Type: "string", Format: ""}) + 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 diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index 966de191e5..cf32c3e258 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -43,11 +43,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, Type: "string", Format: ""}) + 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 diff --git a/internal/test/issues/issue-2232/issue2232.gen.go b/internal/test/issues/issue-2232/issue2232.gen.go index b99598ba4f..a63393b342 100644 --- a/internal/test/issues/issue-2232/issue2232.gen.go +++ b/internal/test/issues/issue-2232/issue2232.gen.go @@ -6,6 +6,7 @@ package issue2232 import ( + "errors" "fmt" "net/http" @@ -81,37 +82,34 @@ type MiddlewareFunc func(http.Handler) http.Handler 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" ------------- - if paramValue := r.URL.Query().Get("env_param_level"); paramValue != "" { - - } else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_param_level"}) - return - } - err = runtime.BindQueryParameterWithOptions("form", true, true, "env_param_level", r.URL.Query(), ¶ms.EnvParamLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_param_level", Err: err}) + 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" ------------- - if paramValue := r.URL.Query().Get("env_schema_level"); paramValue != "" { - - } else { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_schema_level"}) - return - } - err = runtime.BindQueryParameterWithOptions("form", true, true, "env_schema_level", r.URL.Query(), ¶ms.EnvSchemaLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_schema_level", Err: err}) + 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 } @@ -119,7 +117,12 @@ func (siw *ServerInterfaceWrapper) GetEndpoint(w http.ResponseWriter, r *http.Re err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) 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 } 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 index 0b00613664..cbd8ff259e 100644 --- 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 @@ -364,11 +364,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, Type: "string", Format: ""}) + 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 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 93dc41ff9b..19d2761adc 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 @@ -364,11 +364,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, Type: "string", Format: ""}) + 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 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 935b805c1c..ae310f8f39 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 @@ -364,11 +364,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, Type: "string", Format: ""}) + 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 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 50478990af..a8696bf99d 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 @@ -364,11 +364,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, Type: "string", Format: ""}) + 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 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 59d306d519..ca724a735b 100644 --- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go +++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go @@ -364,11 +364,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, Type: "string", Format: ""}) + 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 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..e191f7959c --- /dev/null +++ b/internal/test/parameters/chi/gen/server.gen.go @@ -0,0 +1,1663 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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 69% rename from internal/test/parameters/parameters.gen.go rename to internal/test/parameters/client/gen/client.gen.go index 9a66132841..3da4e16cf9 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" ) @@ -121,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 @@ -242,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) @@ -275,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) @@ -360,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 { @@ -384,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 { @@ -408,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 { @@ -432,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 { @@ -456,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 { @@ -492,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 { @@ -970,6 +1063,40 @@ func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request 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 + } + + return req, nil +} + // NewGetLabelNoExplodeArrayRequest generates requests for GetLabelNoExplodeArray func NewGetLabelNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) { var err error @@ -1038,6 +1165,40 @@ func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Reque 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 + } + + return req, nil +} + // NewGetMatrixExplodeArrayRequest generates requests for GetMatrixExplodeArray func NewGetMatrixExplodeArrayRequest(server string, id []int32) (*http.Request, error) { var err error @@ -1106,6 +1267,40 @@ func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request, 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 + } + + return req, nil +} + // NewGetMatrixNoExplodeArrayRequest generates requests for GetMatrixNoExplodeArray func NewGetMatrixNoExplodeArrayRequest(server string, id []int32) (*http.Request, error) { var err error @@ -1174,6 +1369,40 @@ func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request 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 + } + + return req, nil +} + // NewGetPassThroughRequest generates requests for GetPassThrough func NewGetPassThroughRequest(server string, param string) (*http.Request, error) { var err error @@ -1255,6 +1484,72 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http. 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) + } + } + + } + + 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 +} + // NewGetQueryFormRequest generates requests for GetQueryForm func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Request, error) { var err error @@ -1471,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.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) + pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"}) if err != nil { return nil, err } @@ -1487,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 } @@ -1505,8 +1800,42 @@ 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.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/simpleNoExplodeArray/%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 +} + +// NewGetSimpleNoExplodeObjectRequest generates requests for GetSimpleNoExplodeObject +func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Request, error) { var err error var pathParam0 string @@ -1665,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) @@ -1698,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) @@ -1837,6 +2184,27 @@ func (r GetLabelExplodeObjectResponse) StatusCode() int { return 0 } +type GetLabelExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + type GetLabelNoExplodeArrayResponse struct { Body []byte HTTPResponse *http.Response @@ -1879,6 +2247,27 @@ func (r GetLabelNoExplodeObjectResponse) StatusCode() int { return 0 } +type GetLabelPrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelPrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelPrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetMatrixExplodeArrayResponse struct { Body []byte HTTPResponse *http.Response @@ -1921,6 +2310,27 @@ func (r GetMatrixExplodeObjectResponse) StatusCode() int { return 0 } +type GetMatrixExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixExplodePrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixExplodePrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetMatrixNoExplodeArrayResponse struct { Body []byte HTTPResponse *http.Response @@ -1963,6 +2373,27 @@ func (r GetMatrixNoExplodeObjectResponse) StatusCode() int { return 0 } +type GetMatrixPrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixPrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixPrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetPassThroughResponse struct { Body []byte HTTPResponse *http.Response @@ -2005,6 +2436,27 @@ func (r GetDeepObjectResponse) StatusCode() int { return 0 } +type GetQueryDelimitedResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetQueryDelimitedResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetQueryDelimitedResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetQueryFormResponse struct { Body []byte HTTPResponse *http.Response @@ -2068,6 +2520,27 @@ func (r GetSimpleExplodeObjectResponse) StatusCode() int { return 0 } +type GetSimpleExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + type GetSimpleNoExplodeArrayResponse struct { Body []byte HTTPResponse *http.Response @@ -2206,6 +2679,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...) @@ -2224,6 +2706,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...) @@ -2242,6 +2733,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...) @@ -2260,6 +2760,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...) @@ -2278,6 +2787,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...) @@ -2305,6 +2823,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...) @@ -2437,6 +2964,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) @@ -2469,6 +3012,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) @@ -2501,6 +3060,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) @@ -2533,6 +3108,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) @@ -2565,6 +3156,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) @@ -2613,6 +3220,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) @@ -2676,829 +3299,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, 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 -} - -// 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 -} - -// 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 -} - -// 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 -} - -// 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 -} - -// 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 -} - -// 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 -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router EchoRouter, si ServerInterface) { - RegisterHandlersWithBaseURL(router, si, "") -} - -// Registers handlers, and prepends BaseURL to the paths, so that the paths -// can be served under a prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.GET(baseURL+"/contentObject/:param", wrapper.GetContentObject) - router.GET(baseURL+"/cookie", wrapper.GetCookie) - router.GET(baseURL+"/enums", wrapper.EnumParams) - router.GET(baseURL+"/header", wrapper.GetHeader) - router.GET(baseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray) - router.GET(baseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject) - router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) - router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) - router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) - router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) - router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) - router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) - router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough) - router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject) - router.GET(baseURL+"/queryForm", wrapper.GetQueryForm) - router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) - router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) - router.GET(baseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray) - router.GET(baseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject) - router.GET(baseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive) - router.GET(baseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/9xaUXOjNhD+K8y2Tx1i7Ls+8Za5XtvM9HJpnZnrTCYPCqyDroB0kpwm4+G/dySBAYEx", - "dkyS61uCVvvtfqy+aJdsIGIZZznmSkK4AYGSs1yi+WVJM57iX+Uj/SRiucJc6R8VPqqAp4Tm+jcZJZgR", - "8/yJI4QglaD5PRRF4UOMMhKUK8pyCOHck8avV2F57O4rRgq0qfVj0D8wbfX42S6GG+CCcRSK2uAu4gYa", - "zRXeo4DChwt5Hmc2qHLxjrEUSa4Xa2c/ClxBCD8Edf5BCR58ruMR+G1NBcYQ3lSbfQ1d49y23LZjXFEh", - "1SXJsIcYHwRL+xYcVGPlN1zdGk5pvmJ6c0ojLF9OboDg08W19q6o0u7hGqXyligeUIAPDyikfQ2L2Xw2", - "14aMY044hRDez+azBfjAiUpM/EH5vm1+wYYTQbJCr9yjSVcnS/R71W8DfkP1obnBuBIkQ4VCQnjTqh/C", - "eUojszn4KplTRUOvp10YJRsQmrDBr2gwyNDkUok1Frd+u8bfzee78LZ2gXMQCoMZRIz9Q3GYDWPRoaF9", - "ILigGVX0QRviI09ZjBCuSCqxTCyq3FSpgd+gasVERpQ9BO/fgd85E4U/ClHTswMQn41YosQeEYI8jYUl", - "LViqMJOj8LdPLFpPPJ0whvieLowtLaw6MKN4Ya2AxkmZC91FHKLgOMSpjns7k8ga1Bz2ZhAx6JKg1zyp", - "iFA0v/f+pSrx8nV2Z6Sy18tCtohwpdtVlxhXZJ2qYxUG87UttV6B+ZivsystLHKfwlxVizZF7dZ7IOka", - "ZZXntzWKp0aFGdcquSpFtM5Yr0B4s5jP/Xfz+a0/Qgy6kvuz5ab1JphXVUuZfIIkRjEkr79bi+fKa1K5", - "KZP/++yqsWVSoR2APvtYasOLSG83kHNt3R/EiwnxjqheWY67UVlt6idrCnXeFcF3J9LdREpHVUJHSLbr", - "c3G2LK3PvlCVnF1W1i8m4ym5w7QsDlPAwWZmJOunwbv0H+62rtL1leeYa/BpDpAPUj2ZJsNkCKe8XDc5", - "q9qPQ0nb1YWcgrUxp2tyfi5ZX1Xt56e9b4Cgpuj8j+pqm3+7sg4gbm9pPYe5166tjChBH53SovHwwfvU", - "2XTMwaPx5DVls5uOsG1NHcTY8Vq1h7LDimkycjpSReMR5JxAqL7niurq1GGsPUOl3npVcSLldSLY+j4Z", - "M5e8qs0Hp5IHTLVfZeZo+vRfEHk9ct6VcsNqT4ccI/LhlscZD8TW9dEV4nQLdaHEdcynvoSbFH5lIhvi", - "7M+t0R7KRjXV7lDlVHPEmi+9FQ5sqp2oXiyocc21y9n0o04H8RSA21T3zX/cbKeZ7A9kezpAr9TGHTjD", - "c9NXHkM4wR43KnacHDgpfsbfBPs5tX29GtEpLzvb3u58waYIk7HW+sB5AG1vZ8IwGUPuxX3/XWvZs+8N", - "zximZ2785/Nl38Y3MWWYjKXtB4/x/DQ/zzjMHMXEiOKZkobyb8oXqhI7mw42ixFUdLZN2NgsJu5sNMPm", - "X1Rs3GuRQgiJUjwMgvL/UxRKNdP9QUb4jFAobov/AgAA//8eGGgVvSQAAA==", -} - -// GetSwagger returns the content of the embedded swagger specification file -// or error if failed to decode -func decodeSpec() ([]byte, error) { - zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) - if err != nil { - return nil, fmt.Errorf("error base64 decoding spec: %w", err) - } - zr, err := gzip.NewReader(bytes.NewReader(zipped)) - if err != nil { - return nil, fmt.Errorf("error decompressing spec: %w", err) - } - var buf bytes.Buffer - _, err = buf.ReadFrom(zr) - if err != nil { - return nil, fmt.Errorf("error decompressing spec: %w", err) - } - - return buf.Bytes(), nil -} - -var rawSpec = decodeSpecCached() - -// a naive cached of a decoded swagger spec -func decodeSpecCached() func() ([]byte, error) { - data, err := decodeSpec() - return func() ([]byte, error) { - return data, err - } -} - -// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. -func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { - res := make(map[string]func() ([]byte, error)) - if len(pathToFile) > 0 { - res[pathToFile] = rawSpec - } - - return res -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. The external references of Swagger specification are resolved. -// The logic of resolving external references is tightly connected to "import-mapping" feature. -// Externally referenced files must be embedded in the corresponding golang packages. -// Urls can be supported but this task was out of the scope. -func GetSwagger() (swagger *openapi3.T, err error) { - resolvePath := PathToRawSpec("") - - loader := openapi3.NewLoader() - loader.IsExternalRefsAllowed = true - loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { - pathToFile := url.String() - pathToFile = path.Clean(pathToFile) - getSpec, ok := resolvePath[pathToFile] - if !ok { - err1 := fmt.Errorf("path not found: %s", pathToFile) - return nil, err1 - } - return getSpec() - } - var specData []byte - specData, err = rawSpec() - if err != nil { - return - } - swagger, err = loader.LoadFromData(specData) - if err != nil { - return - } - return -} diff --git a/internal/test/parameters/config.yaml b/internal/test/parameters/config.yaml deleted file mode 100644 index 64850f5de5..0000000000 --- a/internal/test/parameters/config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# yaml-language-server: $schema=../../../configuration-schema.json -package: parameters -generate: - echo-server: true - client: true - models: true - embedded-spec: true -output: parameters.gen.go diff --git a/internal/test/parameters/doc.go b/internal/test/parameters/doc.go index 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..c3c6d36d8f --- /dev/null +++ b/internal/test/parameters/echo/gen/server.gen.go @@ -0,0 +1,977 @@ +// 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/gzip" + "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 +} + +// 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+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive) + router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) + router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) + router.GET(baseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive) + router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) + router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) + router.GET(baseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive) + router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) + router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) + router.GET(baseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive) + router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough) + router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject) + router.GET(baseURL+"/queryDelimited", wrapper.GetQueryDelimited) + router.GET(baseURL+"/queryForm", wrapper.GetQueryForm) + router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) + router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) + router.GET(baseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive) + 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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 0635301dfa..6e6d63bea5 100644 --- a/internal/test/parameters/parameters_test.go +++ b/internal/test/parameters/echo/parameters_test.go @@ -1,29 +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/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() { @@ -36,6 +37,7 @@ func (t *testServer) reset() { t.primitiveString = nil t.cookieParams = nil t.queryParams = nil + t.queryDelimitedParams = nil t.headerParams = nil } @@ -141,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 @@ -267,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() @@ -367,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) @@ -425,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 @@ -515,219 +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() - 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() - 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/Makefile b/internal/test/parameters/echov5/Makefile new file mode 100644 index 0000000000..54df0d106e --- /dev/null +++ b/internal/test/parameters/echov5/Makefile @@ -0,0 +1,45 @@ +GO_VERSION := $(shell go version | sed -E 's/.*go([0-9]+\.[0-9]+).*/\1/') +MIN_VERSION := 1.25 +VERSION_OK := $(shell printf '%s\n%s' '$(MIN_VERSION)' '$(GO_VERSION)' | sort -V | head -1 | grep -q '^$(MIN_VERSION)$$' && echo yes || echo no) + +lint: +ifeq ($(VERSION_OK),yes) + $(GOBIN)/golangci-lint run ./... +else + @echo "Skipping lint: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif + +lint-ci: +ifeq ($(VERSION_OK),yes) + $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m +else + @echo "Skipping lint-ci: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif + +generate: +ifeq ($(VERSION_OK),yes) + go generate ./... +else + @echo "Skipping generate: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif + +test: +ifeq ($(VERSION_OK),yes) + go test -cover ./... +else + @echo "Skipping test: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif + +tidy: +ifeq ($(VERSION_OK),yes) + go mod tidy +else + @echo "Skipping tidy: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif + +tidy-ci: +ifeq ($(VERSION_OK),yes) + tidied -verbose +else + @echo "Skipping tidy-ci: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" +endif diff --git a/internal/test/parameters/echov5/client.cfg.yaml b/internal/test/parameters/echov5/client.cfg.yaml new file mode 100644 index 0000000000..79dabbe746 --- /dev/null +++ b/internal/test/parameters/echov5/client.cfg.yaml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=../../../../configuration-schema.json +package: echov5params +generate: + client: true +output: client.gen.go diff --git a/internal/test/parameters/echov5/client.gen.go b/internal/test/parameters/echov5/client.gen.go new file mode 100644 index 0000000000..09ce4a6ff7 --- /dev/null +++ b/internal/test/parameters/echov5/client.gen.go @@ -0,0 +1,3162 @@ +// Package echov5params 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 echov5params + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/oapi-codegen/runtime" +) + +// 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 { + // GetContentObject request + GetContentObject(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetCookie request + GetCookie(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // EnumParams request + EnumParams(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetHeader request + GetHeader(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetLabelExplodeArray request + GetLabelExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) + + // 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) + + // GetSimpleExplodeArray request + GetSimpleExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) + + // 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) + + // GetSimpleNoExplodeObject request + GetSimpleNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetSimplePrimitive request + GetSimplePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetStartingWithNumber request + GetStartingWithNumber(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) GetContentObject(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetContentObjectRequest(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) GetCookie(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetCookieRequest(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) EnumParams(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewEnumParamsRequest(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) GetHeader(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetHeaderRequest(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) GetLabelExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetLabelExplodeArrayRequest(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) GetLabelExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetLabelExplodeObjectRequest(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) 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 { + 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) GetLabelNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetLabelNoExplodeObjectRequest(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) 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 { + 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) GetMatrixExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetMatrixExplodeObjectRequest(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) 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 { + 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) GetMatrixNoExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetMatrixNoExplodeObjectRequest(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) 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 { + 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) GetDeepObject(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetDeepObjectRequest(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) 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 { + 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) GetSimpleExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetSimpleExplodeArrayRequest(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) GetSimpleExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetSimpleExplodeObjectRequest(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) 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 { + 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) GetSimpleNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetSimpleNoExplodeObjectRequest(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) GetSimplePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetSimplePrimitiveRequest(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) GetStartingWithNumber(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetStartingWithNumberRequest(c.Server, n1param) + 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) +} + +// NewGetContentObjectRequest generates requests for GetContentObject +func NewGetContentObjectRequest(server string, param ComplexObject) (*http.Request, error) { + var err error + + var pathParam0 string + + var pathParamBuf0 []byte + pathParamBuf0, err = json.Marshal(param) + if err != nil { + return nil, err + } + pathParam0 = string(pathParamBuf0) + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/contentObject/%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 +} + +// NewGetCookieRequest generates requests for GetCookie +func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/cookie") + 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.P != nil { + var cookieParam0 string + + cookieParam0, err = runtime.StyleParamWithOptions("simple", false, "p", *params.P, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"}) + if err != nil { + return nil, err + } + + cookie0 := &http.Cookie{ + Name: "p", + Value: cookieParam0, + } + req.AddCookie(cookie0) + } + + if params.Ep != nil { + var cookieParam1 string + + cookieParam1, err = runtime.StyleParamWithOptions("simple", true, "ep", *params.Ep, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"}) + if err != nil { + return nil, err + } + + cookie1 := &http.Cookie{ + Name: "ep", + Value: cookieParam1, + } + req.AddCookie(cookie1) + } + + if params.Ea != nil { + var cookieParam2 string + + cookieParam2, err = runtime.StyleParamWithOptions("simple", true, "ea", *params.Ea, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + cookie2 := &http.Cookie{ + Name: "ea", + Value: cookieParam2, + } + req.AddCookie(cookie2) + } + + if params.A != nil { + var cookieParam3 string + + cookieParam3, err = runtime.StyleParamWithOptions("simple", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + cookie3 := &http.Cookie{ + Name: "a", + Value: cookieParam3, + } + req.AddCookie(cookie3) + } + + if params.Eo != nil { + var cookieParam4 string + + cookieParam4, err = runtime.StyleParamWithOptions("simple", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""}) + if err != nil { + return nil, err + } + + cookie4 := &http.Cookie{ + Name: "eo", + Value: cookieParam4, + } + req.AddCookie(cookie4) + } + + if params.O != nil { + var cookieParam5 string + + cookieParam5, err = runtime.StyleParamWithOptions("simple", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""}) + if err != nil { + return nil, err + } + + cookie5 := &http.Cookie{ + Name: "o", + Value: cookieParam5, + } + req.AddCookie(cookie5) + } + + if params.Co != nil { + var cookieParam6 string + + var cookieParamBuf6 []byte + cookieParamBuf6, err = json.Marshal(*params.Co) + if err != nil { + return nil, err + } + cookieParam6 = url.QueryEscape(string(cookieParamBuf6)) + + cookie6 := &http.Cookie{ + Name: "co", + Value: cookieParam6, + } + req.AddCookie(cookie6) + } + + if params.N1s != nil { + var cookieParam7 string + + cookieParam7, err = runtime.StyleParamWithOptions("simple", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "string", Format: ""}) + if err != nil { + return nil, err + } + + cookie7 := &http.Cookie{ + Name: "1s", + Value: cookieParam7, + } + req.AddCookie(cookie7) + } + } + return req, nil +} + +// NewEnumParamsRequest generates requests for EnumParams +func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/enums") + 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.EnumPathParam != 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 _, 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 +} + +// NewGetHeaderRequest generates requests for GetHeader +func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/header") + 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.XPrimitive != nil { + var headerParam0 string + + 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 + } + + req.Header.Set("X-Primitive", headerParam0) + } + + if params.XPrimitiveExploded != nil { + var headerParam1 string + + 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 + } + + req.Header.Set("X-Primitive-Exploded", headerParam1) + } + + if params.XArrayExploded != nil { + var headerParam2 string + + 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 + } + + req.Header.Set("X-Array-Exploded", headerParam2) + } + + if params.XArray != nil { + var headerParam3 string + + headerParam3, err = runtime.StyleParamWithOptions("simple", false, "X-Array", *params.XArray, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + req.Header.Set("X-Array", headerParam3) + } + + if params.XObjectExploded != nil { + var headerParam4 string + + headerParam4, err = runtime.StyleParamWithOptions("simple", true, "X-Object-Exploded", *params.XObjectExploded, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""}) + if err != nil { + return nil, err + } + + req.Header.Set("X-Object-Exploded", headerParam4) + } + + if params.XObject != nil { + var headerParam5 string + + headerParam5, err = runtime.StyleParamWithOptions("simple", false, "X-Object", *params.XObject, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""}) + if err != nil { + return nil, err + } + + req.Header.Set("X-Object", headerParam5) + } + + if params.XComplexObject != nil { + var headerParam6 string + + var headerParamBuf6 []byte + headerParamBuf6, err = json.Marshal(*params.XComplexObject) + if err != nil { + return nil, err + } + headerParam6 = string(headerParamBuf6) + + req.Header.Set("X-Complex-Object", headerParam6) + } + + if params.N1StartingWithNumber != nil { + var headerParam7 string + + 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 + } + + req.Header.Set("1-Starting-With-Number", headerParam7) + } + + } + + return req, nil +} + +// NewGetLabelExplodeArrayRequest generates requests for GetLabelExplodeArray +func NewGetLabelExplodeArrayRequest(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: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/labelExplodeArray/%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 +} + +// NewGetLabelExplodeObjectRequest generates requests for GetLabelExplodeObject +func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("label", true, "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("/labelExplodeObject/%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 +} + +// 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 + } + + return req, nil +} + +// NewGetLabelNoExplodeArrayRequest generates requests for GetLabelNoExplodeArray +func NewGetLabelNoExplodeArrayRequest(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: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/labelNoExplodeArray/%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 +} + +// NewGetLabelNoExplodeObjectRequest generates requests for GetLabelNoExplodeObject +func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("label", 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("/labelNoExplodeObject/%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 +} + +// 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 + } + + return req, nil +} + +// NewGetMatrixExplodeArrayRequest generates requests for GetMatrixExplodeArray +func NewGetMatrixExplodeArrayRequest(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: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/matrixExplodeArray/%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 +} + +// NewGetMatrixExplodeObjectRequest generates requests for GetMatrixExplodeObject +func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("matrix", true, "id", id, 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("/matrixExplodeObject/%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 +} + +// 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 + } + + return req, nil +} + +// NewGetMatrixNoExplodeArrayRequest generates requests for GetMatrixNoExplodeArray +func NewGetMatrixNoExplodeArrayRequest(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: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/matrixNoExplodeArray/%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 +} + +// NewGetMatrixNoExplodeObjectRequest generates requests for GetMatrixNoExplodeObject +func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("matrix", false, "id", id, 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("/matrixNoExplodeObject/%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 +} + +// 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 + } + + return req, nil +} + +// NewGetPassThroughRequest generates requests for GetPassThrough +func NewGetPassThroughRequest(server string, param string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0 = param + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/passThrough/%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 +} + +// NewGetDeepObjectRequest generates requests for GetDeepObject +func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/queryDeepObject") + 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 queryFrag, err := runtime.StyleParamWithOptions("deepObject", true, "deepObj", params.DeepObj, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", 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 +} + +// 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) + } + } + + } + + 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 +} + +// NewGetQueryFormRequest generates requests for GetQueryForm +func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/queryForm") + 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.Ea != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.A != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.Eo != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.O != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.Ep != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.P != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.Ps != 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 _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } + } + + } + + if params.Co != nil { + + if queryParamBuf, err := json.Marshal(*params.Co); err != nil { + return nil, err + } else { + queryValues.Add("co", string(queryParamBuf)) + } + + } + + if params.N1s != 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 _, 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 +} + +// NewGetSimpleExplodeArrayRequest generates requests for GetSimpleExplodeArray +func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/simpleExplodeArray/%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 +} + +// NewGetSimpleExplodeObjectRequest generates requests for GetSimpleExplodeObject +func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", true, "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("/simpleExplodeObject/%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 +} + +// NewGetSimpleExplodePrimitiveRequest generates requests for GetSimpleExplodePrimitive +func NewGetSimpleExplodePrimitiveRequest(server string, param int32) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", 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("/simpleExplodePrimitive/%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 +} + +// NewGetSimpleNoExplodeArrayRequest generates requests for GetSimpleNoExplodeArray +func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/simpleNoExplodeArray/%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 +} + +// 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.StyleParamWithOptions("simple", 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("/simplePrimitive/%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 +} + +// NewGetStartingWithNumberRequest generates requests for GetStartingWithNumber +func NewGetStartingWithNumberRequest(server string, n1param string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0 = n1param + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/startingWithNumber/%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 { + // GetContentObjectWithResponse request + GetContentObjectWithResponse(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*GetContentObjectResponse, error) + + // GetCookieWithResponse request + GetCookieWithResponse(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*GetCookieResponse, error) + + // EnumParamsWithResponse request + EnumParamsWithResponse(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*EnumParamsResponse, error) + + // GetHeaderWithResponse request + GetHeaderWithResponse(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*GetHeaderResponse, error) + + // GetLabelExplodeArrayWithResponse request + GetLabelExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelExplodeArrayResponse, error) + + // 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) + + // GetSimpleExplodeArrayWithResponse request + GetSimpleExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodeArrayResponse, error) + + // 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) + + // GetSimpleNoExplodeObjectWithResponse request + GetSimpleNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeObjectResponse, error) + + // GetSimplePrimitiveWithResponse request + GetSimplePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimplePrimitiveResponse, error) + + // GetStartingWithNumberWithResponse request + GetStartingWithNumberWithResponse(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*GetStartingWithNumberResponse, error) +} + +type GetContentObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetContentObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetContentObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetCookieResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetCookieResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetCookieResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type EnumParamsResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r EnumParamsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r EnumParamsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetHeaderResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetHeaderResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetHeaderResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetLabelExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelExplodeArrayResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelExplodeArrayResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetLabelExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelExplodeObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelExplodeObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetLabelExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetLabelNoExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelNoExplodeArrayResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelNoExplodeArrayResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetLabelNoExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelNoExplodeObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelNoExplodeObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetLabelPrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetLabelPrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetLabelPrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixExplodeArrayResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixExplodeArrayResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixExplodeObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixExplodeObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixExplodePrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixExplodePrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixNoExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixNoExplodeArrayResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixNoExplodeArrayResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixNoExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixNoExplodeObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixNoExplodeObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetMatrixPrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetMatrixPrimitiveResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetMatrixPrimitiveResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetPassThroughResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetPassThroughResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetPassThroughResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetDeepObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetDeepObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetDeepObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetQueryDelimitedResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetQueryDelimitedResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetQueryDelimitedResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetQueryFormResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetQueryFormResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetQueryFormResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetSimpleExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetSimpleExplodeArrayResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetSimpleExplodeArrayResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetSimpleExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetSimpleExplodeObjectResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetSimpleExplodeObjectResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetSimpleExplodePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetSimpleNoExplodeArrayResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetSimpleNoExplodeObjectResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetSimplePrimitiveResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +type GetStartingWithNumberResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 +} + +// 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) +} + +// GetCookieWithResponse request returning *GetCookieResponse +func (c *ClientWithResponses) GetCookieWithResponse(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*GetCookieResponse, error) { + rsp, err := c.GetCookie(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetCookieResponse(rsp) +} + +// EnumParamsWithResponse request returning *EnumParamsResponse +func (c *ClientWithResponses) EnumParamsWithResponse(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*EnumParamsResponse, error) { + rsp, err := c.EnumParams(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseEnumParamsResponse(rsp) +} + +// GetHeaderWithResponse request returning *GetHeaderResponse +func (c *ClientWithResponses) GetHeaderWithResponse(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*GetHeaderResponse, error) { + rsp, err := c.GetHeader(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetHeaderResponse(rsp) +} + +// GetLabelExplodeArrayWithResponse request returning *GetLabelExplodeArrayResponse +func (c *ClientWithResponses) GetLabelExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelExplodeArrayResponse, error) { + rsp, err := c.GetLabelExplodeArray(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetLabelExplodeArrayResponse(rsp) +} + +// GetLabelExplodeObjectWithResponse request returning *GetLabelExplodeObjectResponse +func (c *ClientWithResponses) GetLabelExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelExplodeObjectResponse, error) { + rsp, err := c.GetLabelExplodeObject(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetLabelNoExplodeArrayResponse(rsp) +} + +// GetLabelNoExplodeObjectWithResponse request returning *GetLabelNoExplodeObjectResponse +func (c *ClientWithResponses) GetLabelNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelNoExplodeObjectResponse, error) { + rsp, err := c.GetLabelNoExplodeObject(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetMatrixExplodeArrayResponse(rsp) +} + +// GetMatrixExplodeObjectWithResponse request returning *GetMatrixExplodeObjectResponse +func (c *ClientWithResponses) GetMatrixExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixExplodeObjectResponse, error) { + rsp, err := c.GetMatrixExplodeObject(ctx, id, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetMatrixNoExplodeArrayResponse(rsp) +} + +// GetMatrixNoExplodeObjectWithResponse request returning *GetMatrixNoExplodeObjectResponse +func (c *ClientWithResponses) GetMatrixNoExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixNoExplodeObjectResponse, error) { + rsp, err := c.GetMatrixNoExplodeObject(ctx, id, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetPassThroughResponse(rsp) +} + +// GetDeepObjectWithResponse request returning *GetDeepObjectResponse +func (c *ClientWithResponses) GetDeepObjectWithResponse(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*GetDeepObjectResponse, error) { + rsp, err := c.GetDeepObject(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetQueryFormResponse(rsp) +} + +// GetSimpleExplodeArrayWithResponse request returning *GetSimpleExplodeArrayResponse +func (c *ClientWithResponses) GetSimpleExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodeArrayResponse, error) { + rsp, err := c.GetSimpleExplodeArray(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetSimpleExplodeArrayResponse(rsp) +} + +// GetSimpleExplodeObjectWithResponse request returning *GetSimpleExplodeObjectResponse +func (c *ClientWithResponses) GetSimpleExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleExplodeObjectResponse, error) { + rsp, err := c.GetSimpleExplodeObject(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + 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...) + if err != nil { + return nil, err + } + return ParseGetSimpleNoExplodeArrayResponse(rsp) +} + +// GetSimpleNoExplodeObjectWithResponse request returning *GetSimpleNoExplodeObjectResponse +func (c *ClientWithResponses) GetSimpleNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeObjectResponse, error) { + rsp, err := c.GetSimpleNoExplodeObject(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetSimpleNoExplodeObjectResponse(rsp) +} + +// GetSimplePrimitiveWithResponse request returning *GetSimplePrimitiveResponse +func (c *ClientWithResponses) GetSimplePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimplePrimitiveResponse, error) { + rsp, err := c.GetSimplePrimitive(ctx, param, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetSimplePrimitiveResponse(rsp) +} + +// GetStartingWithNumberWithResponse request returning *GetStartingWithNumberResponse +func (c *ClientWithResponses) GetStartingWithNumberWithResponse(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*GetStartingWithNumberResponse, error) { + rsp, err := c.GetStartingWithNumber(ctx, n1param, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetStartingWithNumberResponse(rsp) +} + +// ParseGetContentObjectResponse parses an HTTP response from a GetContentObjectWithResponse call +func ParseGetContentObjectResponse(rsp *http.Response) (*GetContentObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetContentObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetCookieResponse parses an HTTP response from a GetCookieWithResponse call +func ParseGetCookieResponse(rsp *http.Response) (*GetCookieResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetCookieResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseEnumParamsResponse parses an HTTP response from a EnumParamsWithResponse call +func ParseEnumParamsResponse(rsp *http.Response) (*EnumParamsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &EnumParamsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetHeaderResponse parses an HTTP response from a GetHeaderWithResponse call +func ParseGetHeaderResponse(rsp *http.Response) (*GetHeaderResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetHeaderResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetLabelExplodeArrayResponse parses an HTTP response from a GetLabelExplodeArrayWithResponse call +func ParseGetLabelExplodeArrayResponse(rsp *http.Response) (*GetLabelExplodeArrayResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetLabelExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetLabelExplodeObjectResponse parses an HTTP response from a GetLabelExplodeObjectWithResponse call +func ParseGetLabelExplodeObjectResponse(rsp *http.Response) (*GetLabelExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetLabelExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetLabelNoExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetLabelNoExplodeObjectResponse parses an HTTP response from a GetLabelNoExplodeObjectWithResponse call +func ParseGetLabelNoExplodeObjectResponse(rsp *http.Response) (*GetLabelNoExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetLabelNoExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetMatrixExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetMatrixExplodeObjectResponse parses an HTTP response from a GetMatrixExplodeObjectWithResponse call +func ParseGetMatrixExplodeObjectResponse(rsp *http.Response) (*GetMatrixExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetMatrixExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetMatrixNoExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetMatrixNoExplodeObjectResponse parses an HTTP response from a GetMatrixNoExplodeObjectWithResponse call +func ParseGetMatrixNoExplodeObjectResponse(rsp *http.Response) (*GetMatrixNoExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetMatrixNoExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetPassThroughResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetDeepObjectResponse parses an HTTP response from a GetDeepObjectWithResponse call +func ParseGetDeepObjectResponse(rsp *http.Response) (*GetDeepObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetDeepObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetQueryFormResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetSimpleExplodeArrayResponse parses an HTTP response from a GetSimpleExplodeArrayWithResponse call +func ParseGetSimpleExplodeArrayResponse(rsp *http.Response) (*GetSimpleExplodeArrayResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSimpleExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetSimpleExplodeObjectResponse parses an HTTP response from a GetSimpleExplodeObjectWithResponse call +func ParseGetSimpleExplodeObjectResponse(rsp *http.Response) (*GetSimpleExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSimpleExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + 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) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSimpleNoExplodeArrayResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetSimpleNoExplodeObjectResponse parses an HTTP response from a GetSimpleNoExplodeObjectWithResponse call +func ParseGetSimpleNoExplodeObjectResponse(rsp *http.Response) (*GetSimpleNoExplodeObjectResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSimpleNoExplodeObjectResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetSimplePrimitiveResponse parses an HTTP response from a GetSimplePrimitiveWithResponse call +func ParseGetSimplePrimitiveResponse(rsp *http.Response) (*GetSimplePrimitiveResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSimplePrimitiveResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetStartingWithNumberResponse parses an HTTP response from a GetStartingWithNumberWithResponse call +func ParseGetStartingWithNumberResponse(rsp *http.Response) (*GetStartingWithNumberResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetStartingWithNumberResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} diff --git a/internal/test/parameters/echov5/echov5_param_test.go b/internal/test/parameters/echov5/echov5_param_test.go new file mode 100644 index 0000000000..12e5eb5206 --- /dev/null +++ b/internal/test/parameters/echov5/echov5_param_test.go @@ -0,0 +1,381 @@ +package echov5params + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/labstack/echo/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestEchoV5ParameterRoundTrip(t *testing.T) { + var s Server + e := echo.New() + RegisterHandlers(e, &s) + testImpl(t, e) +} + +func testImpl(t *testing.T, handler http.Handler) { + t.Helper() + + 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 + + doRoundTrip := func(t *testing.T, req *http.Request, target interface{}) { + t.Helper() + 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") + } + } + + t.Run("path", func(t *testing.T) { + t.Run("simple", func(t *testing.T) { + t.Run("primitive", func(t *testing.T) { + req, err := 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 := 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 := 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 := 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 := NewGetSimpleNoExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got Object + doRoundTrip(t, req, &got) + assert.Equal(t, expectedObject, got) + }) + t.Run("object explode", func(t *testing.T) { + req, err := NewGetSimpleExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got 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 := 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 := 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 := 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 := 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 := NewGetLabelNoExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got Object + doRoundTrip(t, req, &got) + assert.Equal(t, expectedObject, got) + }) + t.Run("object explode", func(t *testing.T) { + req, err := NewGetLabelExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got 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 := 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 := 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 := 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 := 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 := NewGetMatrixNoExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got Object + doRoundTrip(t, req, &got) + assert.Equal(t, expectedObject, got) + }) + t.Run("object explode", func(t *testing.T) { + req, err := NewGetMatrixExplodeObjectRequest(server, expectedObject) + require.NoError(t, err) + var got 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 := NewGetContentObjectRequest(server, expectedComplexObject) + require.NoError(t, err) + var got ComplexObject + doRoundTrip(t, req, &got) + assert.Equal(t, expectedComplexObject, got) + }) + t.Run("passthrough string", func(t *testing.T) { + req, err := NewGetPassThroughRequest(server, "hello world") + require.NoError(t, err) + var got string + doRoundTrip(t, req, &got) + assert.Equal(t, "hello world", got) + }) + }) + }) + + t.Run("query", func(t *testing.T) { + t.Run("form", func(t *testing.T) { + expectedArray2 := []int32{6, 7, 8} + expectedObject2 := 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 := GetQueryFormParams{ + Ea: &expectedArray, A: &expectedArray2, + Eo: &expectedObject, O: &expectedObject2, + Ep: &expectedPrimitive, P: &expectedPrimitive2, + Ps: &expectedPrimitiveString, Co: &expectedComplexObject, N1s: &expectedN1s, + } + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got GetQueryFormParams + doRoundTrip(t, req, &got) + assert.EqualValues(t, params, got) + }) + t.Run("exploded array only", func(t *testing.T) { + params := GetQueryFormParams{Ea: &expectedArray} + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetQueryFormParams{A: &expectedArray} + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetQueryFormParams{Eo: &expectedObject} + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetQueryFormParams{O: &expectedObject} + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetQueryFormParams{Ps: &expectedPrimitiveString} + req, err := NewGetQueryFormRequest(server, ¶ms) + require.NoError(t, err) + var got GetQueryFormParams + doRoundTrip(t, req, &got) + require.NotNil(t, got.Ps) + assert.Equal(t, expectedPrimitiveString, *got.Ps) + }) + }) + t.Run("deepObject", func(t *testing.T) { + params := GetDeepObjectParams{DeepObj: expectedComplexObject} + req, err := NewGetDeepObjectRequest(server, ¶ms) + require.NoError(t, err) + var got GetDeepObjectParams + doRoundTrip(t, req, &got) + assert.Equal(t, expectedComplexObject, got.DeepObj) + }) + t.Run("spaceDelimited", func(t *testing.T) { + }) + t.Run("pipeDelimited", func(t *testing.T) { + }) + }) + + t.Run("header", func(t *testing.T) { + expectedArray2 := []int32{6, 7, 8} + expectedObject2 := 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 := GetHeaderParams{ + XPrimitive: &expectedPrimitive2, XPrimitiveExploded: &expectedPrimitive, + XArrayExploded: &expectedArray, XArray: &expectedArray2, + XObjectExploded: &expectedObject, XObject: &expectedObject2, + XComplexObject: &expectedComplexObject, N1StartingWithNumber: &expectedN1s, + } + req, err := NewGetHeaderRequest(server, ¶ms) + require.NoError(t, err) + var got GetHeaderParams + doRoundTrip(t, req, &got) + assert.EqualValues(t, params, got) + }) + t.Run("primitive only", func(t *testing.T) { + params := GetHeaderParams{XPrimitive: &expectedPrimitive} + req, err := NewGetHeaderRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetHeaderParams{XArray: &expectedArray} + req, err := NewGetHeaderRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetHeaderParams{XObject: &expectedObject} + req, err := NewGetHeaderRequest(server, ¶ms) + require.NoError(t, err) + var got GetHeaderParams + doRoundTrip(t, req, &got) + require.NotNil(t, got.XObject) + assert.Equal(t, expectedObject, *got.XObject) + }) + }) + + t.Run("cookie", func(t *testing.T) { + expectedArray2 := []int32{6, 7, 8} + expectedObject2 := 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 := GetCookieParams{ + P: &expectedPrimitive2, Ep: &expectedPrimitive, + Ea: &expectedArray, A: &expectedArray2, + Eo: &expectedObject, O: &expectedObject2, + Co: &expectedComplexObject, N1s: &expectedN1s, + } + req, err := NewGetCookieRequest(server, ¶ms) + require.NoError(t, err) + var got GetCookieParams + doRoundTrip(t, req, &got) + assert.EqualValues(t, params, got) + }) + t.Run("primitive only", func(t *testing.T) { + params := GetCookieParams{P: &expectedPrimitive} + req, err := NewGetCookieRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetCookieParams{A: &expectedArray} + req, err := NewGetCookieRequest(server, ¶ms) + require.NoError(t, err) + var got 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 := GetCookieParams{O: &expectedObject} + req, err := NewGetCookieRequest(server, ¶ms) + require.NoError(t, err) + var got GetCookieParams + doRoundTrip(t, req, &got) + require.NotNil(t, got.O) + assert.Equal(t, expectedObject, *got.O) + }) + }) +} diff --git a/internal/test/parameters/echov5/go.mod b/internal/test/parameters/echov5/go.mod new file mode 100644 index 0000000000..ee22f25588 --- /dev/null +++ b/internal/test/parameters/echov5/go.mod @@ -0,0 +1,41 @@ +module github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5 + +go 1.25.0 + +replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + +require ( + github.com/getkin/kin-openapi v0.135.0 + github.com/labstack/echo/v5 v5.0.4 + github.com/oapi-codegen/runtime v1.4.0 + github.com/stretchr/testify v1.11.1 +) + +require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.9 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/speakeasy-api/jsonpath v0.6.3 // indirect + github.com/speakeasy-api/openapi v1.19.2 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/internal/test/parameters/echov5/go.sum b/internal/test/parameters/echov5/go.sum new file mode 100644 index 0000000000..4b3a1c089e --- /dev/null +++ b/internal/test/parameters/echov5/go.sum @@ -0,0 +1,190 @@ +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/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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= +github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= +github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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/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/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/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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v5 v5.0.4 h1:ll3I/O8BifjMztj9dD1vx/peZQv8cR2CTUdQK6QxGGc= +github.com/labstack/echo/v5 v5.0.4/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= +github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +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/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/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= +github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= +github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= +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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +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/parameters/echov5/server.cfg.yaml b/internal/test/parameters/echov5/server.cfg.yaml new file mode 100644 index 0000000000..49ef08e89f --- /dev/null +++ b/internal/test/parameters/echov5/server.cfg.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=../../../../configuration-schema.json +package: echov5params +generate: + echo5-server: true + embedded-spec: true +output: server.gen.go diff --git a/internal/test/parameters/echov5/server.gen.go b/internal/test/parameters/echov5/server.gen.go new file mode 100644 index 0000000000..748ae76ad1 --- /dev/null +++ b/internal/test/parameters/echov5/server.gen.go @@ -0,0 +1,977 @@ +// Package echov5params 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 echov5params + +import ( + "bytes" + "compress/gzip" + "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 +} + +// 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+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive) + router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) + router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) + router.GET(baseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive) + router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) + router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) + router.GET(baseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive) + router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) + router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) + router.GET(baseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive) + router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough) + router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject) + router.GET(baseURL+"/queryDelimited", wrapper.GetQueryDelimited) + router.GET(baseURL+"/queryForm", wrapper.GetQueryForm) + router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) + router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) + router.GET(baseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive) + 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/echov5/server.go b/internal/test/parameters/echov5/server.go new file mode 100644 index 0000000000..50e16af349 --- /dev/null +++ b/internal/test/parameters/echov5/server.go @@ -0,0 +1,41 @@ +//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 +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client.cfg.yaml ../parameters.yaml + +package echov5params + +import ( + "net/http" + + "github.com/labstack/echo/v5" +) + +type Server struct{} + +func (s *Server) GetContentObject(ctx *echo.Context, param ComplexObject) error { return (*ctx).JSON(http.StatusOK, param) } +func (s *Server) GetCookie(ctx *echo.Context, params GetCookieParams) error { return (*ctx).JSON(http.StatusOK, params) } +func (s *Server) EnumParams(ctx *echo.Context, params EnumParamsParams) error { return (*ctx).NoContent(http.StatusNoContent) } +func (s *Server) GetHeader(ctx *echo.Context, params 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 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 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 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 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 GetDeepObjectParams) error { return (*ctx).JSON(http.StatusOK, params) } +func (s *Server) GetQueryDelimited(ctx *echo.Context, params GetQueryDelimitedParams) error { return (*ctx).JSON(http.StatusOK, params) } +func (s *Server) GetQueryForm(ctx *echo.Context, params 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 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 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..7cf80b491c --- /dev/null +++ b/internal/test/parameters/echov5/types.cfg.yaml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=../../../../configuration-schema.json +package: echov5params +generate: + models: true +output: types.gen.go diff --git a/internal/test/parameters/echov5/types.gen.go b/internal/test/parameters/echov5/types.gen.go new file mode 100644 index 0000000000..ec30efbad9 --- /dev/null +++ b/internal/test/parameters/echov5/types.gen.go @@ -0,0 +1,143 @@ +// Package echov5params 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 echov5params + +// 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/gen/server.gen.go b/internal/test/parameters/fiber/gen/server.gen.go new file mode 100644 index 0000000000..a615749192 --- /dev/null +++ b/internal/test/parameters/fiber/gen/server.gen.go @@ -0,0 +1,1430 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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..257d7106e0 --- /dev/null +++ b/internal/test/parameters/gin/gen/server.gen.go @@ -0,0 +1,1293 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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..b528089ecb --- /dev/null +++ b/internal/test/parameters/gorilla/gen/server.gen.go @@ -0,0 +1,1496 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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..eff396ab5a --- /dev/null +++ b/internal/test/parameters/iris/gen/server.gen.go @@ -0,0 +1,1132 @@ +// 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/gzip" + "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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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..e0b2fc93d1 --- /dev/null +++ b/internal/test/parameters/param_roundtrip_test.go @@ -0,0 +1,517 @@ +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" + "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" + 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 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) + }) + + 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..520bb3ea46 --- /dev/null +++ b/internal/test/parameters/stdhttp/gen/server.gen.go @@ -0,0 +1,1478 @@ +//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/gzip" + "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("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, 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/{1param}", wrapper.GetStartingWithNumber) + + return m +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", + "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", + "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", + "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", + "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", + "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", + "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", + "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", + "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", + "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", + "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", + "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", + "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", + "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", + "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", + "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", + "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", + "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", + "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", + "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", + "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", + "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", +} + +// 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/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/server/server.gen.go b/internal/test/server/server.gen.go index 67e89ff318..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" @@ -280,6 +281,7 @@ 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 @@ -288,22 +290,25 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re 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.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 } @@ -343,6 +348,7 @@ 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 @@ -377,6 +383,7 @@ 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 @@ -416,6 +423,7 @@ 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 @@ -441,6 +449,7 @@ 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 @@ -458,7 +467,12 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt 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 } @@ -477,6 +491,7 @@ 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 diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 3632359f84..16c02ce305 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -242,6 +242,7 @@ func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *ht func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) { var err error + _ = err // ------------- Path parameter "type" ------------- var pType string @@ -337,6 +338,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 diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index c1b3bd431c..37615230b7 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -191,11 +191,12 @@ func (siw *ServerInterfaceWrapper) RequiredTextBody(c *fiber.Ctx) error { 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, Type: "string", Format: ""}) + 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()) } @@ -309,6 +310,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(c *fiber.Ctx) error { 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 diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index d854ee3cc7..466b116438 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -162,11 +162,12 @@ func (siw *ServerInterfaceWrapper) RequiredTextBody(c *gin.Context) { 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, Type: "string", Format: ""}) + 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 @@ -251,6 +252,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 diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 48846b2438..028b8073bc 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -168,11 +168,12 @@ func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *ht 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, Type: "string", Format: ""}) + 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 @@ -263,6 +264,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 diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 7d81a25fe5..7ae7eb409b 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -124,6 +124,7 @@ func (w *ServerInterfaceWrapper) RequiredTextBody(ctx iris.Context) { func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx iris.Context) { var err error + _ = err // ------------- Path parameter "type" ------------- var pType string @@ -178,6 +179,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 diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 3a14704185..41acd1741f 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -10,7 +10,7 @@ require ( github.com/getkin/kin-openapi v0.135.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.3.1 + github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 ) diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum index dc75c1b597..5a7589c118 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -63,8 +63,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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/oapi-codegen/runtime v1.3.1 h1:RgDY6J4OGQLbRXhG/Xpt3vSVqYpHQS7hN4m85+5xB9g= -github.com/oapi-codegen/runtime v1.3.1/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= +github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= +github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 21e96956c5..e58751b75f 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -169,6 +169,7 @@ func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *ht func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) { var err error + _ = err // ------------- Path parameter "type" ------------- var pType string @@ -264,6 +265,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 diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl index 347b1dd95d..08402e2aca 100644 --- a/pkg/codegen/templates/chi/chi-middleware.tmpl +++ b/pkg/codegen/templates/chi/chi-middleware.tmpl @@ -13,6 +13,7 @@ type MiddlewareFunc func(http.Handler) http.Handler 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}}" ------------- @@ -54,7 +55,7 @@ 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}} @@ -79,7 +80,12 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{if .IsStyled}} 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}} @@ -159,7 +165,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 diff --git a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl index c061240df3..0477ddcd34 100644 --- a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl @@ -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)) } @@ -37,7 +37,7 @@ 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)) } @@ -79,7 +79,7 @@ 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)) } @@ -111,7 +111,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx *echo.Context) error { {{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)) } diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 002d144101..ce20c29a4d 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -14,22 +14,32 @@ 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}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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()) } @@ -57,7 +67,7 @@ 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}} @@ -127,9 +137,10 @@ 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 .HasOptionalPointer}}}&{{end}}cookie @@ -153,7 +164,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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()) } @@ -167,6 +178,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } {{- end}} + } {{end}} {{end}} diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 872590fa7a..87f16a56f8 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -14,23 +14,24 @@ 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}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 @@ -51,7 +52,7 @@ 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}} @@ -155,7 +156,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl index 1624a7ed6a..c971395fb8 100644 --- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl +++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl @@ -13,6 +13,7 @@ type MiddlewareFunc func(http.Handler) http.Handler 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}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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,7 +55,7 @@ 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}} @@ -79,7 +80,12 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{if .IsStyled}} 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}} @@ -159,7 +165,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index 2a6cfaa769..769f2331bc 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -9,15 +9,16 @@ type MiddlewareFunc iris.Handler 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") @@ -53,7 +54,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { return } {{else}} - if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" { + if paramValue := ctx.URLParam("{{.ParamName}}"); paramValue != "" { {{if .IsPassThrough}} params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue {{end}} @@ -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 .HasOptionalPointer}}&{{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}}'") @@ -138,7 +139,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{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}}"}) + 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) diff --git a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl index daadd981a7..00b0208555 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -13,6 +13,7 @@ type MiddlewareFunc func(http.Handler) http.Handler 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}}" ------------- @@ -54,7 +55,7 @@ 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}} @@ -79,7 +80,12 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{if .IsStyled}} 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}} @@ -159,7 +165,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ {{- if .IsStyled}} var value {{.TypeDef}} - err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 From a2219c99dce3dacd590ae14a47495722f22a9dd4 Mon Sep 17 00:00:00 2001 From: Per Buer Date: Tue, 21 Apr 2026 20:50:39 +0200 Subject: [PATCH 233/293] Fix a streaming bug + document streaming through example (#1765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: in GenerateGoSchema(), if a type isn't resolved, the error is swallowed, making it hard to track down * first stab at a streaming example. * generate flushing code if content-type is text/event-stream. * cleanup streaming example. * go mod tidy * comment cleanup. * cleanup after changing the build dependency to 1.21. * try to match the tmpl style of the rest of the template. * changes in template introduced a blank line in the generated code. adding these to git so build doesn't fail. * add a basic README. * remove toolchain directive * add the tools package to help fix deps. * add a test for a streaming endpoint. the server side will stagger writes and the client side will verify that this is happening. buffering will make the tests fail. * update generated code in tests * add the streaming endpoint to all the strict servers * update mod * update mod * updated generate code due to upstream changes. * Undo changes to strict-server example Revert the PR's additions to internal/test/strict-server so the existing harness is left intact. The streaming template change and dedicated example under examples/streaming/ remain. Co-Authored-By: Claude Opus 4.7 (1M context) * Add a streaming client to example Make an end-to-end example, with a client that prints the stream from the server. Co-Authored-By: Claude Opus 4.7 (1M context) * Fix lint issues * Parameterize streaming media types The strict-server template previously hard-coded a single content-type check (text/event-stream) to decide when to generate a flush-per-chunk response path. Replace the string match with a configurable, regex-based mechanism so the decision is declared once and applies to any streaming media type. - Add OutputOptions.StreamingContentTypes (list of regex patterns) and a defaultStreamingContentTypes list of text/event-stream, application/jsonl, and application/x-ndjson. User-provided patterns are merged on top of the defaults. - Compile the merged list up-front: OutputOptions.Validate() rejects invalid regexes via the existing CLI validation gate, and Generate() stashes the compiled regexes in globalState for template access. - Expose ResponseContentDefinition.IsStreamingContentType(), mirroring the existing IsJSON/IsSupported helpers, so strict-interface.tmpl can use {{if .IsStreamingContentType}} instead of an inline string match. The generated streaming code itself is unchanged; only the gate moved. - Document the new option in configuration-schema.json. - Update the streaming example spec from text/event-stream to application/jsonl, which matches what the server actually emits (newline-delimited JSON). The impl.go response-type reference is renamed to track the regenerated type name. application/jsonl is in the default list, so the streaming path still activates. Co-Authored-By: Claude Opus 4.7 (1M context) * streaming support in fiber/iris Port the flush-per-chunk response path from the stdhttp strict template into the fiber and iris variants, gated on the same IsStreamingContentType helper that was just added. Non-streaming responses still use the existing io.Copy call unchanged. - Iris uses the same http.Flusher type-assertion pattern as stdhttp, since iris.ResponseWriter implementations satisfy the interface. Falls back to io.Copy when the assertion fails. - Fiber uses fasthttp's SetBodyStreamWriter callback, which delivers a chunk to the client on each w.Flush() call — the body close moves inside the callback because fasthttp invokes it asynchronously. goimports adds the required bufio import when the streaming branch is actually emitted. The broader drift between the three strict-interface templates is tracked separately in oapi-codegen/oapi-codegen#2331 and is not touched here. Co-Authored-By: Claude Opus 4.7 (1M context) * fix slog key typo in streaming example The server example used "error:" as a slog key, which slog treats as a literal attribute name instead of the intended "error" key. Surfaced by Greptile review on PR #1765. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.7 (1M context) --- configuration-schema.json | 7 + examples/streaming/README.md | 17 + examples/streaming/client/main.go | 52 +++ examples/streaming/client/sse/cfg.yaml | 6 + examples/streaming/client/sse/generate.go | 3 + .../streaming/client/sse/streaming.gen.go | 222 +++++++++++ examples/streaming/sse.yaml | 28 ++ examples/streaming/stdhttp/Makefile | 36 ++ examples/streaming/stdhttp/main.go | 25 ++ examples/streaming/stdhttp/sse/cfg.yaml | 8 + examples/streaming/stdhttp/sse/generate.go | 3 + examples/streaming/stdhttp/sse/impl.go | 89 +++++ .../streaming/stdhttp/sse/streaming.gen.go | 371 ++++++++++++++++++ pkg/codegen/codegen.go | 14 +- pkg/codegen/configuration.go | 40 ++ pkg/codegen/operations.go | 13 + .../strict/strict-fiber-interface.tmpl | 37 +- .../templates/strict/strict-interface.tmpl | 32 +- .../strict/strict-iris-interface.tmpl | 32 +- 19 files changed, 1025 insertions(+), 10 deletions(-) create mode 100644 examples/streaming/README.md create mode 100644 examples/streaming/client/main.go create mode 100644 examples/streaming/client/sse/cfg.yaml create mode 100644 examples/streaming/client/sse/generate.go create mode 100644 examples/streaming/client/sse/streaming.gen.go create mode 100644 examples/streaming/sse.yaml create mode 100644 examples/streaming/stdhttp/Makefile create mode 100644 examples/streaming/stdhttp/main.go create mode 100644 examples/streaming/stdhttp/sse/cfg.yaml create mode 100644 examples/streaming/stdhttp/sse/generate.go create mode 100644 examples/streaming/stdhttp/sse/impl.go create mode 100644 examples/streaming/stdhttp/sse/streaming.gen.go diff --git a/configuration-schema.json b/configuration-schema.json index 21bfb0c0d5..cf5cb3b71c 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -192,6 +192,13 @@ "type": "string" } }, + "streaming-content-types": { + "type": "array", + "description": "Additional regex patterns matched against response Content-Type to decide when the strict server should generate a flush-per-chunk streaming response. Merged with the defaults (text/event-stream, application/jsonl, application/x-ndjson). Invalid regexes fail configuration validation.", + "items": { + "type": "string" + } + }, "nullable-type": { "type": "boolean", "description": "Whether to generate nullable type for nullable fields" 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..65a15573ff --- /dev/null +++ b/examples/streaming/client/sse/streaming.gen.go @@ -0,0 +1,222 @@ +// 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 +} + +// 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 +} + +// 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/Makefile b/examples/streaming/stdhttp/Makefile new file mode 100644 index 0000000000..66f60e4a23 --- /dev/null +++ b/examples/streaming/stdhttp/Makefile @@ -0,0 +1,36 @@ +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/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..a619348ee0 --- /dev/null +++ b/examples/streaming/stdhttp/sse/streaming.gen.go @@ -0,0 +1,371 @@ +//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/gzip" + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/2SSQW/bMAyF/wrB0wY4qZzc9AeGDcU2wD3tptpMwsKiNIkJVhT+7wPlLV2yi2VQeO97", + "fNAbshwS+jdU1pnQ48AxzwRfhm9fH2HQQiGyHGGgcuGRsMMLlcpJ0GO/dVuHS4cpk4TM6HHfRh3moKdq", + "tg/2OZLaMVEdC2dd1d9LuvBEFQLUhoF0aFiY0niOJFrhQxKCTAVmFuog5DzzGMzg4aUmmT/CmEQDi0UM", + "oBypaogZgkxQ6eeZZCSQc3ymssUWtDT55wk9fiJdF8QOC9WcpFILvXPODvMmadH/I9uQfgXryn7/stD3", + "HVoM9Lhzu/2m7zc799Q7v3feuR/WVh1PFIOpcrFAyiv13eO+quF2EytKTwR0IVFbS1+zAVmUjlSMsUa4", + "93m69nPvcEglBkWPU1DaNPXVtmphOeKyXCfp+YVGxcVGt4R/n01T1HOMobz+uYJHFqrv98vyOwAA///z", + "FQ4NgQIAAA==", +} + +// 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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 2d0ed9a0c1..4542635733 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -27,6 +27,7 @@ import ( "maps" "net/http" "os" + "regexp" "runtime/debug" "slices" "sort" @@ -62,6 +63,9 @@ var globalState struct { // 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 @@ -181,6 +185,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { 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 { @@ -208,7 +220,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { 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) } diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index abdab8f049..724444690a 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"` @@ -329,6 +339,12 @@ type OutputOptions struct { // 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"` @@ -384,9 +400,33 @@ func (oo OutputOptions) Validate() map[string]string { } } + 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"` diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 69f8fd9765..8b1a01bd45 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -594,6 +594,19 @@ 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 diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index 11d1cbaad0..b4543b9b20 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -102,11 +102,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}} diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index fc1f53ca01..5814ad1c3a 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -152,8 +152,36 @@ if closer, ok := response.Body.(io.ReadCloser); ok { defer closer.Close() } - _, err := io.Copy(w, response.Body) - return err + {{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 */ -}} } diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index aa7e166d9f..8fcf26da1d 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -107,8 +107,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}} From e3ff50c176206eebab58dc2eefd577edd7fc787a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:19:48 -0700 Subject: [PATCH 234/293] chore(deps): update release-drafter/release-drafter action to v7.2.0 (.github/workflows) (#2322) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 17a281c8cb..ec1c0685ae 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@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7.1.1 + - uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7.2.0 with: name: next tag: next From 6a24613faa869959e4cce2997dff912c1ff1583c Mon Sep 17 00:00:00 2001 From: actatum Date: Tue, 21 Apr 2026 17:11:00 -0400 Subject: [PATCH 235/293] Strictgin error handler (#1600) * adding strictgin-error-handler * gomod * gomod * fix gomod again * fix gomod again * sq * feat: replace single error handler with three-callback pattern in strict gin template Split the single ErrorHandlerFunc into three distinct callbacks to give callers control over error responses by category: - RequestErrorHandlerFunc: request parsing/binding errors (default 400) - HandlerErrorFunc: application handler errors (default 500) - ResponseErrorHandlerFunc: response serialization errors (default 500) This also fixes two bugs in the original template: - Missing multipart boundary now passes http.ErrMissingBoundary instead of a nil error - Unexpected response type now passes a descriptive error instead of nil Co-Authored-By: Claude Opus 4.6 * Update pkg/codegen/templates/strict/strict-gin.tmpl Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Regenerate boilerplate I accepted a Greptile code fix, but this affected generated code. --------- Co-authored-by: Jamie Tanna Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.6 Co-authored-by: Marcin Romaszewicz Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../issues/issue-1093/api/child/child.gen.go | 54 ++++- .../issue-1093/api/parent/parent.gen.go | 54 ++++- .../issue-1208-1209/issue-multi-json.gen.go | 54 ++++- .../test/issues/issue-1212/pkg1/pkg1.gen.go | 54 ++++- .../test/issues/issue-1212/pkg2/pkg2.gen.go | 47 ++++- .../test/issues/issue-1298/issue1298.gen.go | 57 ++++- internal/test/strict-server/gin/server.gen.go | 197 ++++++++++-------- pkg/codegen/templates/strict/strict-gin.tmpl | 78 +++++-- 8 files changed, 463 insertions(+), 132 deletions(-) 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 d6a7ae9bfc..3716a0ba9c 100644 --- a/internal/test/issues/issue-1093/api/child/child.gen.go +++ b/internal/test/issues/issue-1093/api/child/child.gen.go @@ -111,13 +111,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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,14 +179,13 @@ 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)) } } 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 462818dea7..0aada7045e 100644 --- a/internal/test/issues/issue-1093/api/parent/parent.gen.go +++ b/internal/test/issues/issue-1093/api/parent/parent.gen.go @@ -116,13 +116,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 @@ -139,14 +184,13 @@ 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)) } } 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 50ec7337a5..4989ab412c 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 @@ -420,13 +420,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 @@ -443,14 +488,13 @@ 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-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index 50244c424f..643b7e6866 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -320,13 +320,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 @@ -343,14 +388,13 @@ 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-1212/pkg2/pkg2.gen.go b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go index 5a994ed06f..d4c338cce7 100644 --- a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go +++ b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go @@ -189,13 +189,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index a45d921e58..67bb5b92d5 100644 --- a/internal/test/issues/issue-1298/issue1298.gen.go +++ b/internal/test/issues/issue-1298/issue1298.gen.go @@ -358,13 +358,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 @@ -374,8 +419,7 @@ func (sh *strictHandler) Test(ctx *gin.Context) { var body TestApplicationTestPlusJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -392,13 +436,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/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 466b116438..489adcae13 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -1065,13 +1065,58 @@ type StrictServerInterface interface { type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 @@ -1081,8 +1126,7 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) { var body JSONExampleJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -1099,14 +1143,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)) } } @@ -1114,11 +1157,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) { @@ -1131,14 +1174,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)) } } @@ -1147,10 +1189,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) @@ -1166,14 +1208,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)) } } @@ -1186,8 +1227,7 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { var body MultipleRequestAndResponseTypesJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -1196,12 +1236,12 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { } 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 @@ -1210,17 +1250,17 @@ 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 } if len(data) > 0 { @@ -1239,14 +1279,13 @@ 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)) } } @@ -1256,8 +1295,7 @@ func (sh *strictHandler) RequiredJSONBody(ctx *gin.Context) { var body RequiredJSONBodyJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } request.Body = &body @@ -1272,14 +1310,13 @@ func (sh *strictHandler) RequiredJSONBody(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.(RequiredJSONBodyResponseObject); ok { if err := validResponse.VisitRequiredJSONBodyResponse(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)) } } @@ -1289,7 +1326,7 @@ func (sh *strictHandler) RequiredTextBody(ctx *gin.Context) { data, err := io.ReadAll(ctx.Request.Body) if err != nil { - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } body := RequiredTextBodyTextRequestBody(data) @@ -1305,14 +1342,13 @@ func (sh *strictHandler) RequiredTextBody(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.(RequiredTextBodyResponseObject); ok { if err := validResponse.VisitRequiredTextBodyResponse(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)) } } @@ -1332,14 +1368,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)) } } @@ -1350,8 +1385,7 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) { var body ReusableResponsesJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -1368,14 +1402,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)) } } @@ -1385,7 +1418,7 @@ 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 } if len(data) > 0 { @@ -1403,14 +1436,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)) } } @@ -1430,14 +1462,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)) } } @@ -1459,14 +1490,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)) } } @@ -1475,12 +1505,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 @@ -1495,14 +1525,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)) } } @@ -1515,8 +1544,7 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP var body HeadersExampleJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -1533,14 +1561,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)) } } @@ -1551,8 +1578,7 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) { var body UnionExampleJSONRequestBody if err := ctx.ShouldBindJSON(&body); err != nil { if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } } else { @@ -1569,14 +1595,13 @@ 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)) } } diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 86040d6d76..893e4b4046 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -1,13 +1,58 @@ type StrictHandlerFunc = strictgin.StrictGinHandlerFunc type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc +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 .}} @@ -37,13 +82,11 @@ type strictHandler struct { if err := ctx.ShouldBindJSON(&body); err != nil { {{if not .Required -}} if !errors.Is(err, io.EOF) { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return } {{else -}} - ctx.Status(http.StatusBadRequest) - ctx.Error(err) + sh.options.RequestErrorHandlerFunc(ctx, err) return {{end -}} } {{if not .Required -}} else { {{end}} @@ -51,29 +94,29 @@ type strictHandler struct { {{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) @@ -82,7 +125,7 @@ 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 -}} @@ -109,14 +152,13 @@ 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}} From 6a413495c919e7f0058bb6b5d6e5fab02388466b Mon Sep 17 00:00:00 2001 From: Viktoras Makauskas Date: Wed, 22 Apr 2026 04:00:14 +0300 Subject: [PATCH 236/293] fix: include additional types for array response type (#1930) fix: emit additional types for inline array response schemas in strict-server When a response `content` schema was an inline `array` of `object` (e.g. with `additionalProperties: true`), the strict-server template declared `JSONResponse []JSONResponse_Item` but never emitted the `_Item` type itself, so generated code failed to build with `undefined: JSONResponse_Item`. Range over `.Schema.AdditionalTypes` in `strict-interface.tmpl` and emit each type declaration (using `=` for aliases), so inline helper types end up alongside the response type that references them. Adds a test case at `internal/test/issues/issue-1277/` covering models, client, chi-server, and strict-server generation for the repro spec. Fixes #1277 --- internal/test/issues/issue-1277/config.yaml | 8 + .../issues/issue-1277/content-array.gen.go | 489 ++++++++++++++++++ internal/test/issues/issue-1277/generate.go | 3 + internal/test/issues/issue-1277/spec.yaml | 23 + internal/test/strict-server/chi/server.gen.go | 2 + .../test/strict-server/echo/server.gen.go | 2 + internal/test/strict-server/gin/server.gen.go | 2 + .../test/strict-server/gorilla/server.gen.go | 2 + .../test/strict-server/stdhttp/server.gen.go | 2 + .../templates/strict/strict-interface.tmpl | 4 + 10 files changed, 537 insertions(+) create mode 100644 internal/test/issues/issue-1277/config.yaml create mode 100644 internal/test/issues/issue-1277/content-array.gen.go create mode 100644 internal/test/issues/issue-1277/generate.go create mode 100644 internal/test/issues/issue-1277/spec.yaml 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..41eb70440a --- /dev/null +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -0,0 +1,489 @@ +// 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" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// 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_200_Item +} +type Test_200_Item struct { + Field1 *string `json:"field1,omitempty"` + Field2 *string `json:"field2,omitempty"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +// 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 +} + +// 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 []Test_200_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 []Test200JSONResponse_Item + +type Test200JSONResponse_Item struct { + Field1 *string `json:"field1,omitempty"` + Field2 *string `json:"field2,omitempty"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +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 = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +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/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 16c02ce305..a86b27c501 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -1191,6 +1191,8 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } +type UnionExample200JSONResponse0 = string + func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 067448ae36..88036c38f4 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -911,6 +911,8 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } +type UnionExample200JSONResponse0 = string + func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 489adcae13..44d017dbd8 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -986,6 +986,8 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } +type UnionExample200JSONResponse0 = string + func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 028b8073bc..13c5969597 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -1102,6 +1102,8 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } +type UnionExample200JSONResponse0 = string + func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index e58751b75f..2034ce7be7 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -1097,6 +1097,8 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } +type UnionExample200JSONResponse0 = string + func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 5814ad1c3a..a686787c13 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -70,6 +70,10 @@ } {{end}} + {{- range .Schema.AdditionalTypes}} + type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}} + {{- end}} + func (response {{$receiverTypeName}}) Visit{{$opid}}Response(w http.ResponseWriter) error { {{if eq .NameTag "Multipart" -}} writer := multipart.NewWriter(w) From 070fa9306958016ddc72152ed235b2e7067b5743 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 22 Apr 2026 14:25:40 -0700 Subject: [PATCH 237/293] Update YAML package where possible (#2333) Fixes: #2310 All generated and example code now uses go.yaml.in/yaml/v3, however, our own yaml loading is still forced to use an older version due to the yaml overlay package. --- cmd/oapi-codegen/oapi-codegen.go | 20 ++++++++++++++------ examples/authenticated-api/stdhttp/go.mod | 2 +- examples/authenticated-api/stdhttp/go.sum | 2 ++ examples/go.mod | 2 +- examples/go.sum | 2 ++ examples/minimal-server/stdhttp/go.mod | 2 +- examples/minimal-server/stdhttp/go.sum | 2 ++ examples/petstore-expanded/echo-v5/go.mod | 2 +- examples/petstore-expanded/echo-v5/go.sum | 2 ++ examples/petstore-expanded/stdhttp/go.mod | 2 +- examples/petstore-expanded/stdhttp/go.sum | 2 ++ go.mod | 2 +- go.sum | 2 ++ internal/test/go.mod | 2 +- internal/test/go.sum | 2 ++ internal/test/parameters/echov5/go.mod | 2 +- internal/test/parameters/echov5/go.sum | 2 ++ internal/test/schemas/schemas.gen.go | 2 +- internal/test/strict-server/stdhttp/go.mod | 2 +- internal/test/strict-server/stdhttp/go.sum | 2 ++ pkg/codegen/templates/imports.tmpl | 2 +- 21 files changed, 43 insertions(+), 17 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 777697b7b8..604c0b3f0f 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,7 +24,7 @@ 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" @@ -156,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. @@ -281,11 +286,14 @@ func main() { // 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 } diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod index d78e8862e0..31580ce4bd 100644 --- a/examples/authenticated-api/stdhttp/go.mod +++ b/examples/authenticated-api/stdhttp/go.mod @@ -40,12 +40,12 @@ require ( github.com/valyala/fastjson v1.6.7 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.46.0 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.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 index de52d10215..8b6ac5870d 100644 --- a/examples/authenticated-api/stdhttp/go.sum +++ b/examples/authenticated-api/stdhttp/go.sum @@ -126,6 +126,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/examples/go.mod b/examples/go.mod index f0833793ce..547b7aaf10 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -111,6 +111,7 @@ require ( github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect go.uber.org/mock v0.5.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect @@ -123,6 +124,5 @@ require ( golang.org/x/tools v0.42.0 // indirect google.golang.org/protobuf v1.36.9 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 5777a31fe3..df0f0883a7 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -320,6 +320,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +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.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod index 362bef5c56..c5b745f440 100644 --- a/examples/minimal-server/stdhttp/go.mod +++ b/examples/minimal-server/stdhttp/go.mod @@ -21,10 +21,10 @@ require ( github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.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 index bb4e53d852..b20ab9fdc9 100644 --- a/examples/minimal-server/stdhttp/go.sum +++ b/examples/minimal-server/stdhttp/go.sum @@ -97,6 +97,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod index 3a9a5d3ef9..7c1c597790 100644 --- a/examples/petstore-expanded/echo-v5/go.mod +++ b/examples/petstore-expanded/echo-v5/go.mod @@ -32,11 +32,11 @@ require ( github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.42.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum index a653a1f09f..71eb695fb0 100644 --- a/examples/petstore-expanded/echo-v5/go.sum +++ b/examples/petstore-expanded/echo-v5/go.sum @@ -114,6 +114,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod index 0a642f935f..998aff9e8e 100644 --- a/examples/petstore-expanded/stdhttp/go.mod +++ b/examples/petstore-expanded/stdhttp/go.mod @@ -32,10 +32,10 @@ require ( github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.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 index b5ae3a9f9f..d1e7ef7d53 100644 --- a/examples/petstore-expanded/stdhttp/go.sum +++ b/examples/petstore-expanded/stdhttp/go.sum @@ -114,6 +114,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/go.mod b/go.mod index 4d5e7aff80..b2a9469a48 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( github.com/getkin/kin-openapi v0.135.0 github.com/speakeasy-api/openapi v1.19.2 github.com/stretchr/testify v1.11.1 + go.yaml.in/yaml/v3 v3.0.4 golang.org/x/mod v0.33.0 golang.org/x/text v0.34.0 golang.org/x/tools v0.42.0 - gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index bb4e53d852..b20ab9fdc9 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 88b0357176..19764e22c9 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -18,7 +18,7 @@ require ( github.com/oapi-codegen/runtime v1.4.0 github.com/oapi-codegen/testutil v1.1.0 github.com/stretchr/testify v1.11.1 - gopkg.in/yaml.v2 v2.4.0 + go.yaml.in/yaml/v3 v3.0.4 ) require ( diff --git a/internal/test/go.sum b/internal/test/go.sum index 969bd3f82f..b366040590 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -293,6 +293,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +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.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/internal/test/parameters/echov5/go.mod b/internal/test/parameters/echov5/go.mod index ee22f25588..ee133844b5 100644 --- a/internal/test/parameters/echov5/go.mod +++ b/internal/test/parameters/echov5/go.mod @@ -32,10 +32,10 @@ require ( github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/test/parameters/echov5/go.sum b/internal/test/parameters/echov5/go.sum index 4b3a1c089e..67fc9e2b1b 100644 --- a/internal/test/parameters/echov5/go.sum +++ b/internal/test/parameters/echov5/go.sum @@ -110,6 +110,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index fe10c8c7eb..bbfbfa3a0a 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -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" diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod index 41acd1741f..4f1b9151ca 100644 --- a/internal/test/strict-server/stdhttp/go.mod +++ b/internal/test/strict-server/stdhttp/go.mod @@ -33,10 +33,10 @@ require ( github.com/speakeasy-api/openapi v1.19.2 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.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 index 5a7589c118..06ee6318c1 100644 --- a/internal/test/strict-server/stdhttp/go.sum +++ b/internal/test/strict-server/stdhttp/go.sum @@ -110,6 +110,8 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl index 8c76dad36d..4c6260006b 100644 --- a/pkg/codegen/templates/imports.tmpl +++ b/pkg/codegen/templates/imports.tmpl @@ -15,7 +15,7 @@ import ( "encoding/xml" "errors" "fmt" - "gopkg.in/yaml.v2" + "go.yaml.in/yaml/v3" "io" "os" "mime" From dd7d133b0d51a931bd1ad88d1d57fbd25dcc71e7 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 23 Apr 2026 10:42:38 -0700 Subject: [PATCH 238/293] Flagify enum validator generation (#2334) Add an `output-options.skip-enum-validate` flag that suppresses the `Valid()` method generated on enum types. The method is still emitted by default; users whose code defines its own `Valid()` on the same type can now opt out instead of seeing a compile-time conflict. Relates to PR #2227, which introduced the `Valid()` method. Co-authored-by: Claude Opus 4.7 (1M context) --- configuration-schema.json | 4 ++++ pkg/codegen/codegen.go | 5 ++++- pkg/codegen/configuration.go | 6 ++++++ pkg/codegen/schema.go | 3 +++ pkg/codegen/templates/constants.tmpl | 3 ++- 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/configuration-schema.json b/configuration-schema.json index cf5cb3b71c..ae58297f62 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -135,6 +135,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.", diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 4542635733..65b97e9c0d 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -1045,7 +1045,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. diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 724444690a..4652640954 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -319,6 +319,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. diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 167b6c627a..c1ce7708d1 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -200,6 +200,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. diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index df434e5377..07a03a2a38 100644 --- a/pkg/codegen/templates/constants.tmpl +++ b/pkg/codegen/templates/constants.tmpl @@ -12,7 +12,7 @@ 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 { @@ -23,3 +23,4 @@ func (e {{$Enum.TypeName}}) Valid() bool { } } {{end}} +{{end}} From bd48f0c25298ef7644b2383206d899197214687d Mon Sep 17 00:00:00 2001 From: Nelz Date: Thu, 23 Apr 2026 14:29:55 -0700 Subject: [PATCH 239/293] Bug Report: demonstration of overlays and allOf not playing together nicely (#2087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * demonstration of overlays and allOf not playing together nicely * Reorganize bug test case Relocate the overlay+allOf regression reproduction from examples/anyof-allof-oneof/ to internal/test/extensions/allof-merge-extensions/. The examples/ directory is for happy-path usage, not regression artifacts. The submitter's overlay.yaml, overlays.go, and overlays_test.go are moved via git rename (preserving per-line blame); package renamed to match new directory. examples/anyof-allof-oneof/ reverts to a clean anyOf/allOf/oneOf usage example. The bug is tracked at https://github.com/oapi-codegen/oapi-codegen/issues/2335 and is unrelated to overlays — it's in the allOf+x-go-type interaction in pkg/codegen/schema.go and pkg/codegen/merge_schemas.go. Co-Authored-By: Claude Opus 4.7 (1M context) * fix: honor x-go-type on allOf schemas, stop extension leakage (#2335) Two bugs were interacting to silently drop user intent: 1. In GenerateGoSchema, the `allOf` branch early-returned before the `x-go-type` check, so an outer `allOf` schema's own `x-go-type` was ignored. The documented contract ("completely override the definition of this schema") was violated whenever the schema used `allOf`. Fix: move the `x-go-type` check above the `allOf` branch. 2. In mergeOpenapiSchemas, extensions from all allOf members were blindly unioned into the merged schema's extensions. When a member's extensions included an identity-bound directive like `x-go-type`, that directive would leak up and become the merged schema's alias target -- e.g. `Client` with `x-go-type: OverlayClient` composed with `{properties:{id}}` via `allOf` would emit `type ClientWithId = OverlayClient`, silently dropping the Id field. The naive fix of dropping all extensions breaks the common "$ref + sibling extension" idiom (see issue #1957), where allOf is used not for composition but as a workaround for OpenAPI 3.0's $ref-sibling restriction to attach extensions to a ref. Fix: in mergeSchemas, detect which of the two uses applies by checking whether any allOf member is extension-only. If so (decorator idiom), extensions flow through as before. If not (real composition), drop extensions from the merged result -- each source schema's extensions belong to that schema, not to the composed type. Regression test lives in internal/test/extensions/allof-merge-extensions/. Co-Authored-By: Claude Opus 4.7 (1M context) * Implement Greptile suggestions Three review findings addressed on top of the previous fix commit: 1. Narrow the non-decorator extension clearing from "wipe everything" to targeted delete() calls for x-go-type, x-go-type-name, and x-go-type-import. User-defined schema-level extensions and any other non-identity directives now survive allOf composition -- we only have concrete evidence of incorrect aliasing for the identity-bound three. 2. Tighten isExtensionOnlySchema via a zero-value approach. Zero out Extensions plus the documentary/metadata fields that don't affect the generated Go type (Title, Description, Default, Example, ExternalDocs, Deprecated, ReadOnly, WriteOnly, AllowEmptyValue, XML) and the kin-openapi Origin tracker, then reflect.DeepEqual against the zero Schema. Shorter, and default-safe against future kin-openapi field additions: any new structural field would be non-zero and correctly disqualify decorator classification. 3. Extend the regression test to cover the harder Fix 2 path. The original scenario had x-go-type on both Client and ClientWithId, which Fix 1 alone makes pass. New schemas BaseOnly/DerivedNoOverride exercise the case where only the base schema has an x-go-type overlay -- the derived schema must still be emitted as its own struct (with both Name and Extra fields) rather than aliased to OverlayBaseOnly. The struct literal in TestBaseOnlyOverlay won't compile under the buggy codegen because OverlayBaseOnly has no Extra field, giving the test a compile-time check in addition to the runtime assertion. Co-Authored-By: Claude Opus 4.7 (1M context) * Defensively clone extensions before deleting identity keys The delete() calls in mergeSchemas operated on schema.Extensions directly. In the current code this is safe: valueWithPropagatedRef returns a shallow struct copy whose Extensions map is shared with the caller, but mergeOpenapiSchemas always reallocates Extensions before merging, and the n>=2 guard ensures that reallocation has happened by the time we reach the delete. The delete thus operates on a fresh map, not the caller's shared one. That safety is an invariant held by two separate pieces of code (the n>=1 short-circuit, and mergeOpenapiSchemas' make()), neither of which is obvious from reading the delete. Cloning the map before mutating makes the non-aliasing explicit locally and keeps the code correct even if either piece changes (e.g. an allocation-skipping optimization in mergeOpenapiSchemas). maps.Clone(nil) returns nil and delete(nil, ...) is a no-op, so no nil-guard is needed. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.7 (1M context) --- .../allof_merge_extensions.gen.go | 19 ++++ .../allof-merge-extensions/config.yaml | 9 ++ .../allof-merge-extensions/generate.go | 3 + .../allof-merge-extensions/overlay.yaml | 14 +++ .../allof-merge-extensions/overlays.go | 20 +++++ .../allof-merge-extensions/overlays_test.go | 38 ++++++++ .../allof-merge-extensions/spec.yaml | 43 +++++++++ pkg/codegen/merge_schemas.go | 87 +++++++++++++++++++ pkg/codegen/schema.go | 27 +++--- 9 files changed, 247 insertions(+), 13 deletions(-) create mode 100644 internal/test/extensions/allof-merge-extensions/allof_merge_extensions.gen.go create mode 100644 internal/test/extensions/allof-merge-extensions/config.yaml create mode 100644 internal/test/extensions/allof-merge-extensions/generate.go create mode 100644 internal/test/extensions/allof-merge-extensions/overlay.yaml create mode 100644 internal/test/extensions/allof-merge-extensions/overlays.go create mode 100644 internal/test/extensions/allof-merge-extensions/overlays_test.go create mode 100644 internal/test/extensions/allof-merge-extensions/spec.yaml 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/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index 1b21ae3e22..af9a9a8b73 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "maps" + "reflect" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -27,6 +28,35 @@ 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 @@ -59,9 +89,66 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) { 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) } +// 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 schema with its Properties refs // updated if ref itself is external. Otherwise, return ref.Value as-is. func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) { diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index c1ce7708d1..aba59c63e9 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -328,6 +328,20 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { SkipOptionalPointer: skipOptionalPointer, } + // Check x-go-type, which will completely override the definition of this + // 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 := schema.Extensions[extPropGoType]; ok { + typeName, err := extTypeName(extension) + if err != nil { + return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoType, err) + } + outSchema.GoType = typeName + outSchema.DefineViaAlias = true + + return outSchema, nil + } + // 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 @@ -341,19 +355,6 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return mergedSchema, nil } - // Check x-go-type, which will completely override the definition of this - // schema with the provided type. - if extension, ok := schema.Extensions[extPropGoType]; ok { - typeName, err := extTypeName(extension) - if err != nil { - return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoType, err) - } - outSchema.GoType = typeName - outSchema.DefineViaAlias = true - - return outSchema, nil - } - // Schema type and format, eg. string / binary t := schema.Type // Handle objects and empty schemas first as a special case From c6d77f26dab62b8120a611d19651c517d61441b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9cile=20Journeaux?= Date: Thu, 23 Apr 2026 18:08:03 -0400 Subject: [PATCH 240/293] feat(client): Add ContentType() to ClientWithResponses responses (#2173) * feat(client): Add ContentType() to ClientWithResponses responses * Make ContentType() default on Flip the ContentType() method on ClientWithResponses response types from opt-in to default-on. The output option is renamed from `client-response-content-type-function` (enable) to `skip-client-response-content-type` (disable). - pkg/codegen/configuration.go: field renamed to SkipClientResponseContentType - configuration-schema.json: key renamed, description inverted - pkg/codegen/templates/client-with-responses.tmpl: condition inverted - internal/test/issues/issue-240-2149: removed; issue240 restored from upstream/main (original issue 240 bytes-function test is still present and ContentType() is now exercised by every generated client) Regenerated all affected .gen.go files. The resulting diff across generated code is large but purely additive: each response type gains a new ContentType() method; no existing declarations are modified or removed, so downstream users cannot be broken by this change. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.7 (1M context) --- configuration-schema.json | 4 + .../authenticated-api/stdhttp/api/api.gen.go | 16 ++ .../test/any_of/codegen/inline/openapi.gen.go | 8 + .../any_of/codegen/ref_schema/openapi.gen.go | 8 + internal/test/any_of/param/param.gen.go | 8 + internal/test/client/client.gen.go | 64 ++++++ internal/test/issues/issue-1039/client.gen.go | 8 + internal/test/issues/issue-1087/api.gen.go | 8 + internal/test/issues/issue-1180/issue.gen.go | 8 + .../test/issues/issue-1182/pkg1/pkg1.gen.go | 8 + .../test/issues/issue-1189/issue1189.gen.go | 8 + .../issue-1208-1209/issue-multi-json.gen.go | 8 + .../test/issues/issue-1212/pkg1/pkg1.gen.go | 8 + .../issues/issue-1277/content-array.gen.go | 8 + .../test/issues/issue-1298/issue1298.gen.go | 8 + .../test/issues/issue-1397/issue1397.gen.go | 8 + .../issue-1529/strict-echo/issue1529.gen.go | 8 + .../issue-1529/strict-fiber/issue1529.gen.go | 8 + .../issue-1529/strict-iris/issue1529.gen.go | 8 + internal/test/issues/issue-1914/client.gen.go | 16 ++ .../issues/issue-2031/prefer/issue2031.gen.go | 8 + .../test/issues/issue-2190/issue2190.gen.go | 8 + .../test/issues/issue-2238/issue2238.gen.go | 8 + internal/test/issues/issue-312/issue.gen.go | 16 ++ internal/test/issues/issue-52/issue.gen.go | 8 + .../issue-grab_import_names/issue.gen.go | 8 + .../issue-illegal_enum_names/issue.gen.go | 8 + internal/test/issues/issue240/client.gen.go | 16 ++ .../name_conflict_resolution.gen.go | 144 ++++++++++++ .../name_normalizer.gen.go | 8 + .../name_normalizer.gen.go | 8 + .../name_normalizer.gen.go | 8 + .../to-camel-case/name_normalizer.gen.go | 8 + .../unset/name_normalizer.gen.go | 8 + .../test/parameters/client/gen/client.gen.go | 216 ++++++++++++++++++ internal/test/parameters/echov5/client.gen.go | 216 ++++++++++++++++++ internal/test/pathalias/client.gen.go | 16 ++ internal/test/schemas/schemas.gen.go | 80 +++++++ .../test/strict-server/client/client.gen.go | 112 +++++++++ pkg/codegen/configuration.go | 3 + .../templates/client-with-responses.tmpl | 11 + 41 files changed, 1146 insertions(+) diff --git a/configuration-schema.json b/configuration-schema.json index ae58297f62..521b251ad9 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -249,6 +249,10 @@ "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." + }, "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.", diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index b370659441..5a83732c25 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -310,6 +310,14 @@ 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 @@ -332,6 +340,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...) diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index 3f85d9bc2f..b837299d1a 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -238,6 +238,14 @@ func (r GetPetsResponse) StatusCode() int { 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...) diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index 05d763e6ac..0aa30cd67f 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -332,6 +332,14 @@ func (r GetPetsResponse) StatusCode() int { 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...) diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 825bafeefd..694d466b9d 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -396,6 +396,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 13fe998b9a..7a26ea68a2 100644 --- a/internal/test/client/client.gen.go +++ b/internal/test/client/client.gen.go @@ -627,6 +627,14 @@ 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 @@ -648,6 +656,14 @@ 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 @@ -669,6 +685,14 @@ 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 @@ -690,6 +714,14 @@ 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 @@ -711,6 +743,14 @@ 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 @@ -732,6 +772,14 @@ 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 @@ -753,6 +801,14 @@ 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 @@ -774,6 +830,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/issues/issue-1039/client.gen.go b/internal/test/issues/issue-1039/client.gen.go index 43cca8d279..63ef866784 100644 --- a/internal/test/issues/issue-1039/client.gen.go +++ b/internal/test/issues/issue-1039/client.gen.go @@ -227,6 +227,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-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go index cf944315f5..dcbcca53ea 100644 --- a/internal/test/issues/issue-1087/api.gen.go +++ b/internal/test/issues/issue-1087/api.gen.go @@ -225,6 +225,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-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index dd7f244904..37499ca5cc 100644 --- a/internal/test/issues/issue-1180/issue.gen.go +++ b/internal/test/issues/issue-1180/issue.gen.go @@ -211,6 +211,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...) diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index 4773438107..c5111c09d2 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -205,6 +205,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...) diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index 8b0aa4c209..e06d16c824 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -416,6 +416,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...) 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 4989ab412c..a5f1602504 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 @@ -225,6 +225,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...) diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index 643b7e6866..025f02314c 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -207,6 +207,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...) diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index 41eb70440a..be4983aa29 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -207,6 +207,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...) diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index 67bb5b92d5..9d156149f6 100644 --- a/internal/test/issues/issue-1298/issue1298.gen.go +++ b/internal/test/issues/issue-1298/issue1298.gen.go @@ -240,6 +240,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...) diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index a799293922..81bfad13c2 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -281,6 +281,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...) diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index d392436a89..04180c2821 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -211,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...) diff --git a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index 62cd9ce025..8b1ceac003 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -210,6 +210,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...) diff --git a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go index 6d03eef9ce..e2a01bd04a 100644 --- a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -211,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...) diff --git a/internal/test/issues/issue-1914/client.gen.go b/internal/test/issues/issue-1914/client.gen.go index 5628fff078..7af86aac02 100644 --- a/internal/test/issues/issue-1914/client.gen.go +++ b/internal/test/issues/issue-1914/client.gen.go @@ -313,6 +313,14 @@ func (r PostPetResponse) StatusCode() int { 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 @@ -334,6 +342,14 @@ func (r PostPet1234Response) StatusCode() int { 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...) diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go index 2dcb3372d1..936ac9f762 100644 --- a/internal/test/issues/issue-2031/prefer/issue2031.gen.go +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -230,6 +230,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/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index 8cc8570388..0904608db2 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -206,6 +206,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, reqEditors ...RequestEditorFn) (*GetTestResponse, error) { rsp, err := c.GetTest(ctx, reqEditors...) diff --git a/internal/test/issues/issue-2238/issue2238.gen.go b/internal/test/issues/issue-2238/issue2238.gen.go index 043529ebce..16e923002c 100644 --- a/internal/test/issues/issue-2238/issue2238.gen.go +++ b/internal/test/issues/issue-2238/issue2238.gen.go @@ -236,6 +236,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/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index e49ab36cfe..07102f000b 100644 --- a/internal/test/issues/issue-312/issue.gen.go +++ b/internal/test/issues/issue-312/issue.gen.go @@ -311,6 +311,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 @@ -334,6 +342,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...) diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go index 2c57dd3223..d79ef78059 100644 --- a/internal/test/issues/issue-52/issue.gen.go +++ b/internal/test/issues/issue-52/issue.gen.go @@ -219,6 +219,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...) 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 ee161c40e9..08af8f82ed 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -241,6 +241,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...) 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 1da3d74579..277dc53e3f 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -250,6 +250,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...) diff --git a/internal/test/issues/issue240/client.gen.go b/internal/test/issues/issue240/client.gen.go index 2953b8ce4a..2ce39f4154 100644 --- a/internal/test/issues/issue240/client.gen.go +++ b/internal/test/issues/issue240/client.gen.go @@ -253,6 +253,14 @@ 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 @@ -282,6 +290,14 @@ 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...) diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index bc3fb1ba5a..2c42d3c71c 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -1893,6 +1893,14 @@ func (r ListEntitiesResponse) StatusCode() int { 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 @@ -1915,6 +1923,14 @@ func (r PostFooResponse) StatusCode() int { 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 @@ -1937,6 +1953,14 @@ func (r ListItemsResponse2) StatusCode() int { 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 @@ -1959,6 +1983,14 @@ func (r CreateItemResponse2) StatusCode() int { 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 @@ -1981,6 +2013,14 @@ func (r CreateOrderResponse) StatusCode() int { 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 @@ -2003,6 +2043,14 @@ func (r GetOutcomeResponse) StatusCode() int { 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 @@ -2024,6 +2072,14 @@ func (r PostOutcomeResponse) StatusCode() int { 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 @@ -2046,6 +2102,14 @@ func (r SendPayloadResponse) StatusCode() int { 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 @@ -2068,6 +2132,14 @@ func (r CreatePetResponse) StatusCode() int { 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 @@ -2090,6 +2162,14 @@ func (r QueryResponse2) StatusCode() int { 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 @@ -2112,6 +2192,14 @@ func (r GetQuxResponse) StatusCode() int { 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 @@ -2133,6 +2221,14 @@ func (r PostQuxResponse) StatusCode() int { 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 @@ -2155,6 +2251,14 @@ func (r GetRenamedSchemaResponse) StatusCode() int { 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 @@ -2176,6 +2280,14 @@ func (r PostRenamedSchemaResponse) StatusCode() int { 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 @@ -2205,6 +2317,14 @@ func (r PatchResourceResponse) StatusCode() int { 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 @@ -2227,6 +2347,14 @@ func (r GetStatusResponse2) StatusCode() int { 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 @@ -2249,6 +2377,14 @@ func (r GetZapResponse) StatusCode() int { 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 @@ -2270,6 +2406,14 @@ func (r PostZapResponse) StatusCode() int { 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...) 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 index cbd8ff259e..e27de44070 100644 --- 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 @@ -309,6 +309,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...) 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 19d2761adc..0b361107a4 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 @@ -309,6 +309,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...) 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 ae310f8f39..f69341bea8 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 @@ -309,6 +309,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...) 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 a8696bf99d..b79d538332 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 @@ -309,6 +309,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...) 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 ca724a735b..4e8b5399cd 100644 --- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go +++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go @@ -309,6 +309,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...) diff --git a/internal/test/parameters/client/gen/client.gen.go b/internal/test/parameters/client/gen/client.gen.go index 3da4e16cf9..d92fda1dc7 100644 --- a/internal/test/parameters/client/gen/client.gen.go +++ b/internal/test/parameters/client/gen/client.gen.go @@ -2079,6 +2079,14 @@ 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 @@ -2100,6 +2108,14 @@ 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 @@ -2121,6 +2137,14 @@ 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 @@ -2142,6 +2166,14 @@ 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 @@ -2163,6 +2195,14 @@ 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 @@ -2184,6 +2224,14 @@ 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 @@ -2205,6 +2253,14 @@ func (r GetLabelExplodePrimitiveResponse) StatusCode() int { 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 @@ -2226,6 +2282,14 @@ 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 @@ -2247,6 +2311,14 @@ func (r GetLabelNoExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2268,6 +2340,14 @@ func (r GetLabelPrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2289,6 +2369,14 @@ func (r GetMatrixExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2310,6 +2398,14 @@ func (r GetMatrixExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2331,6 +2427,14 @@ func (r GetMatrixExplodePrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2352,6 +2456,14 @@ func (r GetMatrixNoExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2373,6 +2485,14 @@ func (r GetMatrixNoExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2394,6 +2514,14 @@ func (r GetMatrixPrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2415,6 +2543,14 @@ func (r GetPassThroughResponse) StatusCode() int { return 0 } +// 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 @@ -2436,6 +2572,14 @@ func (r GetDeepObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2457,6 +2601,14 @@ func (r GetQueryDelimitedResponse) StatusCode() int { return 0 } +// 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 @@ -2478,6 +2630,14 @@ func (r GetQueryFormResponse) StatusCode() int { return 0 } +// 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 @@ -2499,6 +2659,14 @@ func (r GetSimpleExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2520,6 +2688,14 @@ func (r GetSimpleExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2541,6 +2717,14 @@ func (r GetSimpleExplodePrimitiveResponse) StatusCode() int { 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 @@ -2562,6 +2746,14 @@ func (r GetSimpleNoExplodeArrayResponse) StatusCode() int { 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 @@ -2583,6 +2775,14 @@ func (r GetSimpleNoExplodeObjectResponse) StatusCode() int { 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 @@ -2604,6 +2804,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 "" +} + type GetStartingWithNumberResponse struct { Body []byte HTTPResponse *http.Response @@ -2625,6 +2833,14 @@ func (r GetStartingWithNumberResponse) StatusCode() int { 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...) diff --git a/internal/test/parameters/echov5/client.gen.go b/internal/test/parameters/echov5/client.gen.go index 09ce4a6ff7..a6b498d5ec 100644 --- a/internal/test/parameters/echov5/client.gen.go +++ b/internal/test/parameters/echov5/client.gen.go @@ -1940,6 +1940,14 @@ 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 @@ -1961,6 +1969,14 @@ 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 @@ -1982,6 +1998,14 @@ 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 @@ -2003,6 +2027,14 @@ 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 @@ -2024,6 +2056,14 @@ 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 @@ -2045,6 +2085,14 @@ 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 @@ -2066,6 +2114,14 @@ func (r GetLabelExplodePrimitiveResponse) StatusCode() int { 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 @@ -2087,6 +2143,14 @@ 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 @@ -2108,6 +2172,14 @@ func (r GetLabelNoExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2129,6 +2201,14 @@ func (r GetLabelPrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2150,6 +2230,14 @@ func (r GetMatrixExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2171,6 +2259,14 @@ func (r GetMatrixExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2192,6 +2288,14 @@ func (r GetMatrixExplodePrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2213,6 +2317,14 @@ func (r GetMatrixNoExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2234,6 +2346,14 @@ func (r GetMatrixNoExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2255,6 +2375,14 @@ func (r GetMatrixPrimitiveResponse) StatusCode() int { return 0 } +// 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 @@ -2276,6 +2404,14 @@ func (r GetPassThroughResponse) StatusCode() int { return 0 } +// 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 @@ -2297,6 +2433,14 @@ func (r GetDeepObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2318,6 +2462,14 @@ func (r GetQueryDelimitedResponse) StatusCode() int { return 0 } +// 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 @@ -2339,6 +2491,14 @@ func (r GetQueryFormResponse) StatusCode() int { return 0 } +// 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 @@ -2360,6 +2520,14 @@ func (r GetSimpleExplodeArrayResponse) StatusCode() int { return 0 } +// 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 @@ -2381,6 +2549,14 @@ func (r GetSimpleExplodeObjectResponse) StatusCode() int { return 0 } +// 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 @@ -2402,6 +2578,14 @@ func (r GetSimpleExplodePrimitiveResponse) StatusCode() int { 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 @@ -2423,6 +2607,14 @@ func (r GetSimpleNoExplodeArrayResponse) StatusCode() int { 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 @@ -2444,6 +2636,14 @@ func (r GetSimpleNoExplodeObjectResponse) StatusCode() int { 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 @@ -2465,6 +2665,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 "" +} + type GetStartingWithNumberResponse struct { Body []byte HTTPResponse *http.Response @@ -2486,6 +2694,14 @@ func (r GetStartingWithNumberResponse) StatusCode() int { 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...) diff --git a/internal/test/pathalias/client.gen.go b/internal/test/pathalias/client.gen.go index d1ee30f777..1339886349 100644 --- a/internal/test/pathalias/client.gen.go +++ b/internal/test/pathalias/client.gen.go @@ -243,6 +243,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 "" +} + type GetTestAlias0Response struct { Body []byte HTTPResponse *http.Response @@ -265,6 +273,14 @@ func (r GetTestAlias0Response) StatusCode() int { 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...) diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index bbfbfa3a0a..828428a84a 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -828,6 +828,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 @@ -851,6 +859,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 @@ -876,6 +892,14 @@ 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 @@ -897,6 +921,14 @@ 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 @@ -918,6 +950,14 @@ 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 @@ -939,6 +979,14 @@ 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 @@ -961,6 +1009,14 @@ 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 @@ -982,6 +1038,14 @@ 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 @@ -1003,6 +1067,14 @@ 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 @@ -1025,6 +1097,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...) diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 66eeb2014c..72a328818a 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -1205,6 +1205,14 @@ 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 @@ -1226,6 +1234,14 @@ 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 @@ -1247,6 +1263,14 @@ 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 @@ -1269,6 +1293,14 @@ 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 RequiredJSONBodyResponse struct { Body []byte HTTPResponse *http.Response @@ -1291,6 +1323,14 @@ func (r RequiredJSONBodyResponse) StatusCode() int { 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 @@ -1312,6 +1352,14 @@ func (r RequiredTextBodyResponse) StatusCode() int { 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 @@ -1333,6 +1381,14 @@ 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 @@ -1355,6 +1411,14 @@ 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 @@ -1376,6 +1440,14 @@ 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 @@ -1397,6 +1469,14 @@ 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 @@ -1418,6 +1498,14 @@ 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 @@ -1439,6 +1527,14 @@ 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 @@ -1461,6 +1557,14 @@ 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 @@ -1487,6 +1591,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...) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 4652640954..7938aa9fdb 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -371,6 +371,9 @@ type OutputOptions struct { // 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"` diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index 3b85500a8d..8b5b670be6 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -81,6 +81,17 @@ 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}} From 097bc33cf46c4cd824e94fc968dd5f3694fc2ff3 Mon Sep 17 00:00:00 2001 From: Paul Mach Date: Fri, 24 Apr 2026 23:13:40 -0700 Subject: [PATCH 241/293] support all x-* extensions and with ref (#1880) * support `x-go-type` and `x-go-type-import` with ref * support all other extensions and with ref * Fix code review feedback Greptile pointed out that we lost a guard on x-go-import, so put it back. * Honor ref-sibling extensions in allOf merge and parameter schemas PR #1880 introduced combinedSchemaExtensions so extensions placed next to a $ref are honored, with ref-side winning over value-side. The helper is wired in at GenerateGoSchema and Property.Extensions, but three other consumers of *openapi3.SchemaRef extensions still read value-side only and silently shadow the ref-side siblings. This commit closes the remaining gaps. * pkg/codegen/merge_schemas.go - valueWithPropagatedRef now folds ref.Extensions into the returned schema's Extensions via combinedSchemaExtensions, so allOf members can carry per-use sibling directives without mutating the referenced schema. Also returns a shallow copy unconditionally with a fresh Extensions map so callers can't back-mutate the source SchemaRef. - mergeAllOf routes each member through valueWithPropagatedRef instead of dereferencing schemaRef.Value directly, so the transitively-flattened nested-allOf path inherits the same fix. - The "real composition drops type-identity extensions" delete block at lines 105-109 is unchanged; it now strips ref-side x-go-type / x-go-type-name / x-go-type-import the same way it strips value-side, since both end up in schema.Extensions under the same keys. The allof-merge-extensions fixture remains bit-identical. * pkg/codegen/operations.go - GenerateParamsTypes uses combinedSchemaExtensions(param.Spec.Schema) when building the *Params struct field's extension map, so a sibling extension on a parameter's $ref schema (e.g. x-omitempty: false next to a $ref) reaches the field. * internal/test/extensions/param-ref-sibling-omitempty/ - New regression fixture exercising the Gap 3 fix: a query parameter whose schema is a $ref with sibling x-omitempty: false now generates json:"filter" instead of json:"filter,omitempty". * internal/test/go.mod - make tidy promotes golang.org/x/time from indirect to direct (used by the x-go-type fixture's generated file from PR #1880). --------- Co-authored-by: Marcin Romaszewicz --- .../param-ref-sibling-omitempty/config.yaml | 8 + .../param-ref-sibling-omitempty/generate.go | 3 + .../param-ref-sibling-omitempty/issue.gen.go | 267 ++++++++++++++++++ .../param-ref-sibling-omitempty/spec.yaml | 22 ++ .../config.yaml | 7 + .../generate.go | 3 + .../issue.gen.go | 17 ++ .../x-go-type-skip-optional-pointer/spec.yaml | 18 ++ .../test/extensions/x-go-type/config.yaml | 7 + .../test/extensions/x-go-type/generate.go | 3 + .../test/extensions/x-go-type/issue.gen.go | 19 ++ internal/test/extensions/x-go-type/spec.yaml | 25 ++ .../x-oapi-codegen-extra-tags/config.yaml | 7 + .../x-oapi-codegen-extra-tags/generate.go | 3 + .../x-oapi-codegen-extra-tags/issue.gen.go | 14 + .../x-oapi-codegen-extra-tags/spec.yaml | 22 ++ .../test/extensions/x-omitempty/config.yaml | 7 + .../test/extensions/x-omitempty/generate.go | 3 + .../test/extensions/x-omitempty/issue.gen.go | 17 ++ .../test/extensions/x-omitempty/spec.yaml | 18 ++ internal/test/go.mod | 2 +- pkg/codegen/codegen.go | 13 +- pkg/codegen/merge_schemas.go | 23 +- pkg/codegen/operations.go | 11 +- pkg/codegen/schema.go | 56 +++- pkg/codegen/utils.go | 21 +- 26 files changed, 586 insertions(+), 30 deletions(-) create mode 100644 internal/test/extensions/param-ref-sibling-omitempty/config.yaml create mode 100644 internal/test/extensions/param-ref-sibling-omitempty/generate.go create mode 100644 internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go create mode 100644 internal/test/extensions/param-ref-sibling-omitempty/spec.yaml create mode 100644 internal/test/extensions/x-go-type-skip-optional-pointer/config.yaml create mode 100644 internal/test/extensions/x-go-type-skip-optional-pointer/generate.go create mode 100644 internal/test/extensions/x-go-type-skip-optional-pointer/issue.gen.go create mode 100644 internal/test/extensions/x-go-type-skip-optional-pointer/spec.yaml create mode 100644 internal/test/extensions/x-go-type/config.yaml create mode 100644 internal/test/extensions/x-go-type/generate.go create mode 100644 internal/test/extensions/x-go-type/issue.gen.go create mode 100644 internal/test/extensions/x-go-type/spec.yaml create mode 100644 internal/test/extensions/x-oapi-codegen-extra-tags/config.yaml create mode 100644 internal/test/extensions/x-oapi-codegen-extra-tags/generate.go create mode 100644 internal/test/extensions/x-oapi-codegen-extra-tags/issue.gen.go create mode 100644 internal/test/extensions/x-oapi-codegen-extra-tags/spec.yaml create mode 100644 internal/test/extensions/x-omitempty/config.yaml create mode 100644 internal/test/extensions/x-omitempty/generate.go create mode 100644 internal/test/extensions/x-omitempty/issue.gen.go create mode 100644 internal/test/extensions/x-omitempty/spec.yaml 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..1cc7a983d3 --- /dev/null +++ b/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go @@ -0,0 +1,267 @@ +// 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 +} + +// 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/go.mod b/internal/test/go.mod index 19764e22c9..1a1e9b4ed5 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -19,6 +19,7 @@ require ( 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.14.0 ) require ( @@ -106,7 +107,6 @@ require ( golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.42.0 // indirect google.golang.org/protobuf v1.36.9 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 65b97e9c0d..8514ef83e1 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -1334,15 +1334,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 diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index af9a9a8b73..bc887cfa3b 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -149,11 +149,17 @@ func isExtensionOnlySchema(s *openapi3.Schema) bool { return reflect.DeepEqual(tmp, openapi3.Schema{}) } -// valueWithPropagatedRef returns a copy of ref schema with its Properties refs -// updated if ref itself is external. Otherwise, return ref.Value as-is. +// 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, "#") @@ -162,8 +168,6 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) { } remoteComponent := pathParts[0] - // remote ref - schema := *ref.Value for _, value := range schema.Properties { if len(value.Ref) > 0 && value.Ref[0] == '#' { // local reference, should propagate remote @@ -184,7 +188,14 @@ func mergeAllOf(allOf []*openapi3.SchemaRef, seenSchemaRef map[string]bool) (ope if schemaRef.Ref != "" { seenSchemaRef[schemaRef.Ref] = true } - schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true, seenSchemaRef) + // 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) } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 8b1a01bd45..ec395284e7 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -1073,11 +1073,14 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { Schema: param.Schema, }) } - // Merge extensions from the schema level and the parameter level. - // Parameter-level extensions take precedence over schema-level ones. + // 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 && param.Spec.Schema.Value != nil { - maps.Copy(extensions, param.Spec.Schema.Value.Extensions) + if param.Spec.Schema != nil { + maps.Copy(extensions, combinedSchemaExtensions(param.Spec.Schema)) } maps.Copy(extensions, param.Spec.Extensions) prop := Property{ diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index aba59c63e9..f9c7338161 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -3,6 +3,7 @@ package codegen import ( "errors" "fmt" + "maps" "slices" "strings" @@ -291,12 +292,13 @@ 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 := schema.Extensions[extPropGoTypeSkipOptionalPointer]; ok { + if extension, ok := extensions[extPropGoTypeSkipOptionalPointer]; ok { var err error skipOptionalPointer, err = extParsePropGoTypeSkipOptionalPointer(extension) if err != nil { @@ -307,18 +309,32 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // 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, SkipOptionalPointer: skipOptionalPointer, + OAPISchema: schema, }, nil } @@ -331,7 +347,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // Check x-go-type, which will completely override the definition of this // 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 := schema.Extensions[extPropGoType]; ok { + if extension, ok := extensions[extPropGoType]; ok { typeName, err := extTypeName(extension) if err != nil { return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoType, err) @@ -466,6 +482,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { if p.Value != nil { description = p.Value.Description } + prop := Property{ JsonFieldName: pName, Schema: pSchema, @@ -474,7 +491,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) @@ -500,7 +517,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) @@ -536,7 +553,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 @@ -564,7 +581,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // Allow overriding autogenerated enum type names, since these may // 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) @@ -931,3 +948,18 @@ func setSkipOptionalPointerForContainerType(outSchema *Schema) { 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 +} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index fb921b58a2..df1593645b 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -1080,11 +1080,28 @@ 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]any) if !ok { From f0626c2a7f6a6045b8f94f8918a583d9a18bd099 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 08:39:48 -0700 Subject: [PATCH 242/293] sanitize param names for http.ServeMux (#2279) * sanitize param names for http.ServeMux Go's net/http ServeMux requires wildcard segment names to be valid Go identifiers. OpenAPI specs can use path parameter names containing dashes (e.g. "addressing-identifier"), which causes a panic when registering routes with ServeMux. Fix by sanitizing parameter names in the stdhttp code path: - SwaggerUriToStdHttpUri now sanitizes param names via SanitizeGoIdentity so route patterns use valid Go identifiers (e.g. {addressing_identifier}) - stdhttp middleware template uses new SanitizedParamName for r.PathValue() calls to match the sanitized route pattern, while keeping the original ParamName for error messages - Add SanitizedParamName() method to ParameterDefinition for use by templates that need the sanitized form Add server-specific test directory with per-router integration tests exercising dashed path parameter names. Right now, only stdhttp has a test in this directory, but we'll do router specific tests in there in the future. Fixes #2278 Co-Authored-By: Claude Sonnet 4.6 * Regenerate boilerplate --------- Co-authored-by: Claude Sonnet 4.6 --- .../test/parameters/stdhttp/gen/server.gen.go | 4 +- internal/test/server-specific/spec.yaml | 24 +++ .../test/server-specific/stdhttp/config.yaml | 6 + internal/test/server-specific/stdhttp/doc.go | 3 + .../server-specific/stdhttp/server.gen.go | 180 ++++++++++++++++++ .../server-specific/stdhttp/server_test.go | 33 ++++ pkg/codegen/operations.go | 8 + .../stdhttp/std-http-middleware.tmpl | 6 +- pkg/codegen/utils.go | 28 ++- pkg/codegen/utils_test.go | 7 + 10 files changed, 287 insertions(+), 12 deletions(-) create mode 100644 internal/test/server-specific/spec.yaml create mode 100644 internal/test/server-specific/stdhttp/config.yaml create mode 100644 internal/test/server-specific/stdhttp/doc.go create mode 100644 internal/test/server-specific/stdhttp/server.gen.go create mode 100644 internal/test/server-specific/stdhttp/server_test.go diff --git a/internal/test/parameters/stdhttp/gen/server.gen.go b/internal/test/parameters/stdhttp/gen/server.gen.go index 520bb3ea46..06afd09a22 100644 --- a/internal/test/parameters/stdhttp/gen/server.gen.go +++ b/internal/test/parameters/stdhttp/gen/server.gen.go @@ -1214,7 +1214,7 @@ func (siw *ServerInterfaceWrapper) GetStartingWithNumber(w http.ResponseWriter, // ------------- Path parameter "1param" ------------- var n1param string - n1param = r.PathValue("1param") + n1param = r.PathValue("_param") handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.GetStartingWithNumber(w, r, n1param) @@ -1373,7 +1373,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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/{1param}", wrapper.GetStartingWithNumber) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/startingWithNumber/{_param}", wrapper.GetStartingWithNumber) return m } 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/pkg/codegen/operations.go b/pkg/codegen/operations.go index ec395284e7..ce0e98d2f0 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -153,6 +153,14 @@ func (pd *ParameterDefinition) SchemaFormat() string { 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) { diff --git a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl index 00b0208555..8058ed1714 100644 --- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl +++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl @@ -20,17 +20,17 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ 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}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}) + 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 diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index df1593645b..bc1763ed5b 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -628,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*} @@ -646,7 +647,10 @@ func SwaggerUriToStdHttpUri(uri string) string { return "/{$}" } - return pathParamRE.ReplaceAllString(uri, "{$1}") + 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 @@ -745,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 { @@ -758,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 diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 3f9e0e8b76..9afe8b2d2e 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -454,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) { From a10a2a22fdc5e01430d7da1684f5f58adfb9d4e6 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 28 Feb 2026 07:49:17 -0800 Subject: [PATCH 243/293] fix: support x-oapi-codegen-extra-tags on path params in strict-server RequestObject ParameterDefinition.JsonTag() only produced a `json:"..."` tag and ignored x-oapi-codegen-extra-tags. This meant path parameters in strict-server RequestObject structs never included extra struct tags, even though query/header/cookie parameters did (via GenerateParamsTypes). Update JsonTag() to read x-oapi-codegen-extra-tags from both the parameter and schema levels, with parameter-level taking precedence, matching the existing merge behavior in GenerateParamsTypes(). Fixes #2261 Co-Authored-By: Claude Opus 4.6 --- pkg/codegen/operations.go | 36 ++++++++++++++- pkg/codegen/operations_test.go | 82 ++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index ce0e98d2f0..b933d10289 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -66,12 +66,44 @@ func (pd ParameterDefinition) ZeroValueIsNil() bool { // 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 { diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go index 0eff03e2c2..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) { @@ -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()) + }) +} From 5b562c422adce153bc26ec31d05b5ae323dd4315 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 3 Mar 2026 11:53:25 -0800 Subject: [PATCH 244/293] Inline strict middleware typedefs Replace type aliases to runtime/strictmiddleware/* packages with inline type definitions in all strict server templates. This removes the unnecessary runtime dependency for StrictHandlerFunc and StrictMiddlewareFunc, and updates interface{} to any in the fiber template for consistency. Closes #2270 Co-Authored-By: Claude Opus 4.6 --- .../issues/issue-1093/api/child/child.gen.go | 5 ++--- .../issue-1093/api/parent/parent.gen.go | 5 ++--- .../test/issues/issue-1182/pkg1/pkg1.gen.go | 5 ++--- .../test/issues/issue-1182/pkg2/pkg2.gen.go | 5 ++--- .../issue-1208-1209/issue-multi-json.gen.go | 5 ++--- .../test/issues/issue-1212/pkg1/pkg1.gen.go | 5 ++--- .../test/issues/issue-1212/pkg2/pkg2.gen.go | 5 ++--- .../issues/issue-1277/content-array.gen.go | 5 ++--- .../test/issues/issue-1298/issue1298.gen.go | 5 ++--- .../issue-1378/bionicle/bionicle.gen.go | 5 ++--- .../issues/issue-1378/common/common.gen.go | 6 +++--- .../issue-1378/fooservice/fooservice.gen.go | 5 ++--- .../issue-1529/strict-echo/issue1529.gen.go | 5 ++--- .../issue-1529/strict-fiber/issue1529.gen.go | 3 +-- .../issue-1529/strict-iris/issue1529.gen.go | 5 ++--- internal/test/issues/issue-1676/ping.gen.go | 5 ++--- .../test/issues/issue-1963/issue1963.gen.go | 5 ++--- .../test/issues/issue-2113/gen/api/api.gen.go | 5 ++--- .../test/issues/issue-2190/issue2190.gen.go | 6 ++---- .../gen/spec_base/issue.gen.go | 5 ++--- .../gen/spec_ext/issue.gen.go | 6 +++--- internal/test/strict-server/chi/server.gen.go | 5 ++--- .../test/strict-server/echo/server.gen.go | 5 ++--- .../test/strict-server/fiber/server.gen.go | 3 +-- internal/test/strict-server/gin/server.gen.go | 5 ++--- .../test/strict-server/gorilla/server.gen.go | 5 ++--- .../test/strict-server/iris/server.gen.go | 5 ++--- .../test/strict-server/stdhttp/server.gen.go | 5 ++--- pkg/codegen/configuration.go | 21 ------------------- pkg/codegen/templates/strict/strict-echo.tmpl | 4 ++-- .../templates/strict/strict-echo5.tmpl | 4 ++-- .../templates/strict/strict-fiber.tmpl | 3 +-- pkg/codegen/templates/strict/strict-gin.tmpl | 4 ++-- pkg/codegen/templates/strict/strict-http.tmpl | 4 ++-- pkg/codegen/templates/strict/strict-iris.tmpl | 4 ++-- 35 files changed, 67 insertions(+), 116 deletions(-) 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 3716a0ba9c..d50664c315 100644 --- a/internal/test/issues/issue-1093/api/child/child.gen.go +++ b/internal/test/issues/issue-1093/api/child/child.gen.go @@ -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. @@ -108,8 +107,8 @@ 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 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 0aada7045e..6f6f7d869b 100644 --- a/internal/test/issues/issue-1093/api/parent/parent.gen.go +++ b/internal/test/issues/issue-1093/api/parent/parent.gen.go @@ -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. @@ -113,8 +112,8 @@ 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 diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index c5111c09d2..5baac42d25 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -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 @@ -312,8 +311,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} diff --git a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go index 51eece40aa..df4e45e12d 100644 --- a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go +++ b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go @@ -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 @@ -181,8 +180,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} 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 a5f1602504..72270f9356 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 @@ -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. @@ -425,8 +424,8 @@ 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 diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index 025f02314c..2b4d87954a 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -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 @@ -325,8 +324,8 @@ 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 diff --git a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go index d4c338cce7..1aeee27bac 100644 --- a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go +++ b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go @@ -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,8 +185,8 @@ 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 diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index be4983aa29..8a0c29b2e3 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -14,7 +14,6 @@ import ( "strings" "github.com/go-chi/chi/v5" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // RequestEditorFn is the function signature for the RequestEditor callback function @@ -443,8 +442,8 @@ type StrictServerInterface interface { Test(ctx context.Context, request TestRequestObject) (TestResponseObject, 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-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index 9d156149f6..3d79747d26 100644 --- a/internal/test/issues/issue-1298/issue1298.gen.go +++ b/internal/test/issues/issue-1298/issue1298.gen.go @@ -15,7 +15,6 @@ import ( "strings" "github.com/gin-gonic/gin" - strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin" ) // Test defines model for Test. @@ -363,8 +362,8 @@ 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 diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index ad3c48fb16..f708015ae6 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -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. @@ -235,8 +234,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) diff --git a/internal/test/issues/issue-1378/common/common.gen.go b/internal/test/issues/issue-1378/common/common.gen.go index d1747783e0..0e725531e7 100644 --- a/internal/test/issues/issue-1378/common/common.gen.go +++ b/internal/test/issues/issue-1378/common/common.gen.go @@ -6,6 +6,7 @@ package common import ( "bytes" "compress/gzip" + "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) diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index cf32c3e258..9c856f981b 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -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. @@ -228,8 +227,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) diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index 04180c2821..5356f847bb 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -18,7 +18,6 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/labstack/echo/v4" - strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo" ) // Test defines model for Test. @@ -377,8 +376,8 @@ type StrictServerInterface interface { Test(ctx context.Context, request TestRequestObject) (TestResponseObject, 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} diff --git a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index 8b1ceac003..4ead2d3d10 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -369,8 +369,7 @@ type StrictServerInterface interface { Test(ctx context.Context, request TestRequestObject) (TestResponseObject, 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 { diff --git a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go index e2a01bd04a..0a990102f2 100644 --- a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -18,7 +18,6 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/kataras/iris/v12" - strictiris "github.com/oapi-codegen/runtime/strictmiddleware/iris" ) // Test defines model for Test. @@ -353,8 +352,8 @@ type StrictServerInterface interface { Test(ctx context.Context, request TestRequestObject) (TestResponseObject, 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} diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go index 395033a2ba..30229f8183 100644 --- a/internal/test/issues/issue-1676/ping.gen.go +++ b/internal/test/issues/issue-1676/ping.gen.go @@ -9,7 +9,6 @@ import ( "net/http" "github.com/gorilla/mux" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // ServerInterface represents all server handlers. @@ -195,8 +194,8 @@ type StrictServerInterface interface { GetPing(ctx context.Context, request GetPingRequestObject) (GetPingResponseObject, 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-1963/issue1963.gen.go b/internal/test/issues/issue-1963/issue1963.gen.go index 15164e4b62..b2968de7b7 100644 --- a/internal/test/issues/issue-1963/issue1963.gen.go +++ b/internal/test/issues/issue-1963/issue1963.gen.go @@ -15,7 +15,6 @@ import ( "net/http" "github.com/oapi-codegen/runtime" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // Request defines model for Request. @@ -405,8 +404,8 @@ type StrictServerInterface interface { TextEndpoint(ctx context.Context, request TextEndpointRequestObject) (TextEndpointResponseObject, 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-2113/gen/api/api.gen.go b/internal/test/issues/issue-2113/gen/api/api.gen.go index 626e5ea1f6..9aa3018f10 100644 --- a/internal/test/issues/issue-2113/gen/api/api.gen.go +++ b/internal/test/issues/issue-2113/gen/api/api.gen.go @@ -12,7 +12,6 @@ import ( "github.com/go-chi/chi/v5" externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2113/gen/common" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // ServerInterface represents all server handlers. @@ -233,8 +232,8 @@ type StrictServerInterface interface { ListThings(ctx context.Context, request ListThingsRequestObject) (ListThingsResponseObject, 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-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index 0904608db2..db31e6c1c3 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -14,8 +14,6 @@ import ( "net/http" "net/url" "strings" - - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // Success defines model for Success. @@ -447,8 +445,8 @@ type StrictServerInterface interface { GetTest(ctx context.Context, request GetTestRequestObject) (GetTestResponseObject, 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_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go index f96b78c9b2..57ad01efb4 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 @@ -12,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. @@ -266,8 +265,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/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index a86b27c501..e5a9ebb9d0 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -22,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. @@ -1269,8 +1268,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) diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 88036c38f4..414667b5b5 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -22,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. @@ -989,8 +988,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} diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index 37615230b7..bdb00bfcdb 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -1087,8 +1087,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 { diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 44d017dbd8..0e5e4bd7f1 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -22,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. @@ -1064,8 +1063,8 @@ 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 diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 13c5969597..9b3f8315ea 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -22,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. @@ -1180,8 +1179,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) diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 7ae7eb409b..66d0dce0bb 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -22,7 +22,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. @@ -922,8 +921,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} diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 2034ce7be7..74e78af517 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -23,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. @@ -1175,8 +1174,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) diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 7938aa9fdb..f0a549a897 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -153,41 +153,20 @@ func (g GenerateOptions) RouterImports() []AdditionalImport { switch { case g.EchoServer: imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v4"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictecho", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo"}) - } case g.Echo5Server: imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v5"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictecho5", Package: "github.com/oapi-codegen/runtime/strictmiddleware/echo-v5"}) - } case g.ChiServer: imports = append(imports, AdditionalImport{Package: "github.com/go-chi/chi/v5"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) - } case g.GinServer: imports = append(imports, AdditionalImport{Package: "github.com/gin-gonic/gin"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictgin", Package: "github.com/oapi-codegen/runtime/strictmiddleware/gin"}) - } case g.GorillaServer: imports = append(imports, AdditionalImport{Package: "github.com/gorilla/mux"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) - } 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"}) - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictiris", Package: "github.com/oapi-codegen/runtime/strictmiddleware/iris"}) - } case g.StdHTTPServer: - if g.Strict { - imports = append(imports, AdditionalImport{Alias: "strictnethttp", Package: "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"}) - } } return imports diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl index f8b523fa91..7981c76b9e 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} diff --git a/pkg/codegen/templates/strict/strict-echo5.tmpl b/pkg/codegen/templates/strict/strict-echo5.tmpl index 1073714599..a7e617c1ae 100644 --- a/pkg/codegen/templates/strict/strict-echo5.tmpl +++ b/pkg/codegen/templates/strict/strict-echo5.tmpl @@ -1,5 +1,5 @@ -type StrictHandlerFunc = strictecho5.StrictEchoHandlerFunc -type StrictMiddlewareFunc = strictecho5.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} diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl index 106f33a766..786a11aef8 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 { diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 893e4b4046..167bff762e 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -1,5 +1,5 @@ -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 diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl index d55341ca0b..16a902456c 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) diff --git a/pkg/codegen/templates/strict/strict-iris.tmpl b/pkg/codegen/templates/strict/strict-iris.tmpl index 804efb0cf3..f6342ee37a 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} From 6ac5bddaaa6c2a989f6ea903eff813161c66583a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 09:14:37 -0700 Subject: [PATCH 245/293] Update Greptile settings All code review is now automatic, and I gave Greptile a set of code review suggestions, which we will update as we learn to use it better. --- .greptile/config.json | 5 ++++ .greptile/rules.md | 66 +++++++++++++++++++++++++++++++++++++++++++ greptile.json | 4 --- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 .greptile/config.json create mode 100644 .greptile/rules.md delete mode 100644 greptile.json diff --git a/.greptile/config.json b/.greptile/config.json new file mode 100644 index 0000000000..5fe0cdf421 --- /dev/null +++ b/.greptile/config.json @@ -0,0 +1,5 @@ +{ + "strictness": 2, + "commentTypes": ["logic", "syntax"] +} + diff --git a/.greptile/rules.md b/.greptile/rules.md new file mode 100644 index 0000000000..4384b267c7 --- /dev/null +++ b/.greptile/rules.md @@ -0,0 +1,66 @@ +# 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. 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/greptile.json b/greptile.json deleted file mode 100644 index bc3cc79fc0..0000000000 --- a/greptile.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "skipReview": "AUTOMATIC", - "ignorePatterns": "**/*.gen.go" -} From 2620715239c67a28b41e6fc6a204c63c72aefeda Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 09:27:54 -0700 Subject: [PATCH 246/293] Update .greptile/config.json Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .greptile/config.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.greptile/config.json b/.greptile/config.json index 5fe0cdf421..e301f7f66f 100644 --- a/.greptile/config.json +++ b/.greptile/config.json @@ -1,5 +1,13 @@ +{ { "strictness": 2, - "commentTypes": ["logic", "syntax"] + "commentTypes": ["logic", "syntax"], + "fileSettings": [ + { + "pattern": "**/*.gen.go", + "strictness": 1, + "commentTypes": ["logic"] + } + ] } From 44f8bb62abd4cf0ff15f3622580ce14003ff8820 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 21 Apr 2026 09:09:03 -0700 Subject: [PATCH 247/293] fix: pointer skipping for client query params Closes: #2329 Parameter-level x-go-type-skip-optional-pointer: true on a map- or slice-typed query parameter produced a struct field without a pointer (correct) but a client builder that still dereferenced it (*params.Field), so the generated package failed to compile. The params-struct path in GenStructFromSchema already read the parameter-level extension; DescribeParameters did not, leaving Schema.SkipOptionalPointer false on the ParameterDefinition that backs the client template. Mirror the override there. Also extend ZeroValueIsNil to recognize map[K]V so the emitted nil-check is not dropped when the optional pointer is skipped. Adds a regression fixture under internal/test/issues/issue-2329 covering both the deepObject map and form-style slice cases. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/test/issues/issue-2329/config.yaml | 5 + internal/test/issues/issue-2329/generate.go | 3 + .../test/issues/issue-2329/issue2329.gen.go | 269 ++++++++++++++++++ .../test/issues/issue-2329/issue2329_test.go | 47 +++ internal/test/issues/issue-2329/openapi.yaml | 27 ++ pkg/codegen/operations.go | 25 +- 6 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 internal/test/issues/issue-2329/config.yaml create mode 100644 internal/test/issues/issue-2329/generate.go create mode 100644 internal/test/issues/issue-2329/issue2329.gen.go create mode 100644 internal/test/issues/issue-2329/issue2329_test.go create mode 100644 internal/test/issues/issue-2329/openapi.yaml 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..c16222c930 --- /dev/null +++ b/internal/test/issues/issue-2329/issue2329.gen.go @@ -0,0 +1,269 @@ +// 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 ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/oapi-codegen/runtime" +) + +// ListThingsParams defines parameters for ListThings. +type ListThingsParams struct { + Tags map[string]string `json:"tags,omitempty"` + Labels []string `form:"labels,omitempty" json:"labels,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 { + // 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.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 +} + +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 +} + +// 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 +} + +// 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/issues/issue-2329/issue2329_test.go b/internal/test/issues/issue-2329/issue2329_test.go new file mode 100644 index 0000000000..b7456f6a5e --- /dev/null +++ b/internal/test/issues/issue-2329/issue2329_test.go @@ -0,0 +1,47 @@ +package issue2329 + +import ( + "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") + }) +} diff --git a/internal/test/issues/issue-2329/openapi.yaml b/internal/test/issues/issue-2329/openapi.yaml new file mode 100644 index 0000000000..692bc8b1a7 --- /dev/null +++ b/internal/test/issues/issue-2329/openapi.yaml @@ -0,0 +1,27 @@ +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 diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index b933d10289..4933e35964 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -52,15 +52,21 @@ 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 -// Will return true if the OpenAPI `type` is: -// - `array` +// 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 } - return pd.Schema.OAPISchema.Type.Is("array") + 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 @@ -258,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". From 5e2edce5b6bbdc08b803487e61b395ea5acb7320 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 09:34:02 -0700 Subject: [PATCH 248/293] Regenerate boilerplate --- internal/test/issues/issue-2329/issue2329.gen.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/test/issues/issue-2329/issue2329.gen.go b/internal/test/issues/issue-2329/issue2329.gen.go index c16222c930..22692c0969 100644 --- a/internal/test/issues/issue-2329/issue2329.gen.go +++ b/internal/test/issues/issue-2329/issue2329.gen.go @@ -243,6 +243,14 @@ 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 "" +} + // ListThingsWithResponse request returning *ListThingsResponse func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*ListThingsResponse, error) { rsp, err := c.ListThings(ctx, params, reqEditors...) From e8a39e18a21d2989add5ed66541e9a105dd8440a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 09:42:22 -0700 Subject: [PATCH 249/293] fix: pointer skipping for body schema map properties Property.ZeroValueIsNil mirrored ParameterDefinition.ZeroValueIsNil only for arrays. A map-typed property on a body schema with a custom MarshalJSON (i.e. one with additionalProperties or in oneOf/anyOf) and x-go-type-skip-optional-pointer: true emitted no nil-check, so an unset map field serialised as `"field":null` while an unset slice field with the same flag was omitted. Mirror the map-prefix check from operations.go so both kinds of zero value are treated consistently in the additional-properties / union / union-and-additional-properties templates. Extends the issue-2329 fixture with a Thing body schema covering both map and slice properties; the regression test marshals a zero-value Thing and asserts neither field appears in the JSON object. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/test/components/components.gen.go | 8 +- .../test/issues/issue-2329/issue2329.gen.go | 231 ++++++++++++++++++ .../test/issues/issue-2329/issue2329_test.go | 33 +++ internal/test/issues/issue-2329/openapi.yaml | 27 ++ pkg/codegen/schema.go | 14 +- pkg/codegen/schema_test.go | 8 + 6 files changed, 314 insertions(+), 7 deletions(-) diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index 0bfc1747e6..e8550c87b3 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -647,9 +647,11 @@ 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) + 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) diff --git a/internal/test/issues/issue-2329/issue2329.gen.go b/internal/test/issues/issue-2329/issue2329.gen.go index 22692c0969..06e9baa719 100644 --- a/internal/test/issues/issue-2329/issue2329.gen.go +++ b/internal/test/issues/issue-2329/issue2329.gen.go @@ -4,7 +4,9 @@ package issue2329 import ( + "bytes" "context" + "encoding/json" "fmt" "io" "net/http" @@ -14,12 +16,105 @@ import ( "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 @@ -95,6 +190,11 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption { 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) { @@ -109,6 +209,30 @@ func (c *Client) ListThings(ctx context.Context, params *ListThingsParams, reqEd 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 @@ -175,6 +299,46 @@ func NewListThingsRequest(server string, params *ListThingsParams) (*http.Reques 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 { @@ -220,6 +384,11 @@ func WithBaseURL(baseURL string) ClientOption { 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 { @@ -251,6 +420,35 @@ func (r ListThingsResponse) ContentType() string { return "" } +type CreateThingResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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...) @@ -260,6 +458,23 @@ func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, params 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) @@ -275,3 +490,19 @@ func ParseListThingsResponse(rsp *http.Response) (*ListThingsResponse, error) { 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 index b7456f6a5e..cb534dc05e 100644 --- a/internal/test/issues/issue-2329/issue2329_test.go +++ b/internal/test/issues/issue-2329/issue2329_test.go @@ -1,6 +1,7 @@ package issue2329 import ( + "encoding/json" "testing" "github.com/stretchr/testify/assert" @@ -45,3 +46,35 @@ func TestNewListThingsRequest(t *testing.T) { 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 index 692bc8b1a7..43c53b5775 100644 --- a/internal/test/issues/issue-2329/openapi.yaml +++ b/internal/test/issues/issue-2329/openapi.yaml @@ -25,3 +25,30 @@ paths: 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/pkg/codegen/schema.go b/pkg/codegen/schema.go index f9c7338161..928fad1146 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -153,15 +153,21 @@ 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 -// Will return true if the OpenAPI `type` is: -// - `array` +// 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 } - return p.Schema.OAPISchema.Type.Is("array") + if p.Schema.OAPISchema.Type.Is("array") { + return true + } + + return strings.HasPrefix(p.Schema.GoType, "map[") } // EnumDefinition holds type information for enum diff --git a/pkg/codegen/schema_test.go b/pkg/codegen/schema_test.go index 6075594a32..77c1a8751a 100644 --- a/pkg/codegen/schema_test.go +++ b/pkg/codegen/schema_test.go @@ -465,6 +465,7 @@ func TestProperty_ZeroValueIsNil(t *testing.T) { tests := []struct { name string oapiSchema *openapi3.Schema + goType string expectIsNil bool }{ { @@ -477,6 +478,12 @@ func TestProperty_ZeroValueIsNil(t *testing.T) { 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")}, @@ -509,6 +516,7 @@ func TestProperty_ZeroValueIsNil(t *testing.T) { prop := Property{ Schema: Schema{ OAPISchema: tt.oapiSchema, + GoType: tt.goType, }, } if tt.expectIsNil { From 5260c72055d42244c9f4c21f8358991bb1fd43c5 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 21 Apr 2026 15:02:45 -0700 Subject: [PATCH 250/293] fix: delegate MarshalJSON on strict response types wrapping union refs When a strict-server response content schema is a $ref to a oneOf/anyOf union, the generated response type (e.g. `type X200JSONResponse Event`) is a named defined type and does not inherit Event's MarshalJSON, so json.Encode emits {} for the union's unexported raw message. Generate delegating MarshalJSON/UnmarshalJSON on the response type when the underlying schema is a ref to a union. Inline unions continue to work via the existing $hasUnionElements template branch. Fixes #970. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/test/issues/issue-970/config.yaml | 6 + internal/test/issues/issue-970/generate.go | 3 + .../test/issues/issue-970/issue970.gen.go | 375 ++++++++++++++++++ .../test/issues/issue-970/issue970_test.go | 64 +++ internal/test/issues/issue-970/spec.yaml | 33 ++ pkg/codegen/schema.go | 20 + .../strict/strict-fiber-interface.tmpl | 10 + .../templates/strict/strict-interface.tmpl | 10 + .../strict/strict-iris-interface.tmpl | 10 + .../templates/strict/strict-responses.tmpl | 10 + 10 files changed, 541 insertions(+) create mode 100644 internal/test/issues/issue-970/config.yaml create mode 100644 internal/test/issues/issue-970/generate.go create mode 100644 internal/test/issues/issue-970/issue970.gen.go create mode 100644 internal/test/issues/issue-970/issue970_test.go create mode 100644 internal/test/issues/issue-970/spec.yaml 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/pkg/codegen/schema.go b/pkg/codegen/schema.go index 928fad1146..499a36c390 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -65,6 +65,26 @@ 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. +// +// It is deliberately false for inline unions: 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. +func (s Schema) HasCustomMarshalJSON() bool { + if s.OAPISchema == nil { + return false + } + if len(s.UnionElements) > 0 { + return false + } + return len(s.OAPISchema.OneOf) > 0 || len(s.OAPISchema.AnyOf) > 0 +} + func (s Schema) TypeDecl() string { if s.IsRef() { return s.RefType diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index b4543b9b20..bcf372a35c 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -49,6 +49,16 @@ {{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}} diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index a686787c13..947b781fa6 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -49,6 +49,16 @@ {{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}} diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 8fcf26da1d..75b1d792ec 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -51,6 +51,16 @@ {{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}} diff --git a/pkg/codegen/templates/strict/strict-responses.tmpl b/pkg/codegen/templates/strict/strict-responses.tmpl index 74f5d96494..5b4ee68c8d 100644 --- a/pkg/codegen/templates/strict/strict-responses.tmpl +++ b/pkg/codegen/templates/strict/strict-responses.tmpl @@ -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}} From 7787164d95fb2a983d21623c01ea19e273193274 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 23 Mar 2026 11:34:41 -0700 Subject: [PATCH 251/293] Add missing case to type generation traversal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: #1306 GenerateTypeDefsForOperation() was extracting AdditionalTypes from params and request bodies, but not from response content schemas. This meant that x-go-type-name on an inline response schema was silently ignored — the type definition was created internally but never collected for output. Add the missing loop over op.Responses[].Contents[].Schema to extract AdditionalTypes, matching the existing pattern for params and bodies. Extend the xgotypename example with a response-level x-go-type-name test case. Due to this bug, we've neglected to generate types for any types defined inline in responses, so a lot of generated files were affected due to those types being missing. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/extensions/xgotypename/api.yaml | 15 +++ examples/extensions/xgotypename/gen.go | 5 + .../test/any_of/codegen/inline/openapi.gen.go | 5 + .../issues/issue-1277/content-array.gen.go | 96 +++++++++++++++++-- .../name_conflict_resolution.gen.go | 12 +++ internal/test/strict-server/chi/server.gen.go | 2 - internal/test/strict-server/chi/types.gen.go | 3 + .../test/strict-server/client/client.gen.go | 3 + .../test/strict-server/echo/server.gen.go | 2 - internal/test/strict-server/echo/types.gen.go | 3 + .../test/strict-server/fiber/types.gen.go | 3 + internal/test/strict-server/gin/server.gen.go | 2 - internal/test/strict-server/gin/types.gen.go | 3 + .../test/strict-server/gorilla/server.gen.go | 2 - .../test/strict-server/gorilla/types.gen.go | 3 + internal/test/strict-server/iris/types.gen.go | 3 + .../test/strict-server/stdhttp/server.gen.go | 2 - .../test/strict-server/stdhttp/types.gen.go | 3 + pkg/codegen/operations.go | 6 ++ .../templates/strict/strict-interface.tmpl | 4 - 20 files changed, 157 insertions(+), 20 deletions(-) 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/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index b837299d1a..3e9467cb7f 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -48,6 +48,11 @@ type Rat struct { // apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme type apiKeyAuthContextKey string +// GetPets200JSONResponse_Data_Item defines parameters for GetPets. +type GetPets200JSONResponse_Data_Item struct { + union json.RawMessage +} + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index 8a0c29b2e3..fee7e80abb 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -16,6 +16,96 @@ import ( "github.com/go-chi/chi/v5" ) +// Test200JSONResponse_Item defines parameters for Test. +type Test200JSONResponse_Item struct { + Field1 *string `json:"field1,omitempty"` + Field2 *string `json:"field2,omitempty"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +// Getter for additional properties for Test200JSONResponse_Item. Returns the specified +// element and whether it was found +func (a Test200JSONResponse_Item) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for Test200JSONResponse_Item +func (a *Test200JSONResponse_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 Test200JSONResponse_Item to handle AdditionalProperties +func (a *Test200JSONResponse_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 Test200JSONResponse_Item to handle AdditionalProperties +func (a Test200JSONResponse_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 @@ -417,12 +507,6 @@ type TestResponseObject interface { type Test200JSONResponse []Test200JSONResponse_Item -type Test200JSONResponse_Item struct { - Field1 *string `json:"field1,omitempty"` - Field2 *string `json:"field2,omitempty"` - AdditionalProperties map[string]interface{} `json:"-"` -} - func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index 2c42d3c71c..348bcff460 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -258,6 +258,18 @@ type QueryJSONBody struct { Q *string `json:"q,omitempty"` } +// PatchResource200ApplicationJSONPatchPlusJSONResponse1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponse1 = []Resource + +// PatchResource200ApplicationJSONPatchPlusJSONResponse2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponse2 = string + +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 = []Resource + +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 = string + // PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. type PostFooJSONRequestBody PostFooJSONBody diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index e5a9ebb9d0..caf622b4b2 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -1190,8 +1190,6 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } -type UnionExample200JSONResponse0 = string - func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/chi/types.gen.go +++ b/internal/test/strict-server/chi/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 72a328818a..5efe7502b1 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -39,6 +39,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 414667b5b5..3a314fb909 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -910,8 +910,6 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } -type UnionExample200JSONResponse0 = string - func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/echo/types.gen.go +++ b/internal/test/strict-server/echo/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/fiber/types.gen.go +++ b/internal/test/strict-server/fiber/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 0e5e4bd7f1..00ea144ab2 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -985,8 +985,6 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } -type UnionExample200JSONResponse0 = string - func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/gin/types.gen.go +++ b/internal/test/strict-server/gin/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 9b3f8315ea..2c28c12eb4 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -1101,8 +1101,6 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } -type UnionExample200JSONResponse0 = string - func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/gorilla/types.gen.go b/internal/test/strict-server/gorilla/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/gorilla/types.gen.go +++ b/internal/test/strict-server/gorilla/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/iris/types.gen.go b/internal/test/strict-server/iris/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/iris/types.gen.go +++ b/internal/test/strict-server/iris/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index 74e78af517..ac8d245c8d 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -1096,8 +1096,6 @@ type UnionExample200JSONResponse struct { Headers UnionExample200ResponseHeaders } -type UnionExample200JSONResponse0 = string - func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error { var buf bytes.Buffer diff --git a/internal/test/strict-server/stdhttp/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go index fac014c4bb..532c5ebae3 100644 --- a/internal/test/strict-server/stdhttp/types.gen.go +++ b/internal/test/strict-server/stdhttp/types.gen.go @@ -26,6 +26,9 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } +// UnionExample200JSONResponse0 defines parameters for UnionExample. +type UnionExample200JSONResponse0 = string + // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 4933e35964..0fedc32be2 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -1104,6 +1104,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 } diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 947b781fa6..f722f51a91 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -80,10 +80,6 @@ } {{end}} - {{- range .Schema.AdditionalTypes}} - type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}} - {{- end}} - func (response {{$receiverTypeName}}) Visit{{$opid}}Response(w http.ResponseWriter) error { {{if eq .NameTag "Multipart" -}} writer := multipart.NewWriter(w) From 1c89479b095e99cfe31a2f6c2d128d5ccd8ee909 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 14:27:43 -0700 Subject: [PATCH 252/293] Propagate external refs through allOf/anyOf/oneOf/not sub-schemas (#2299) When an external schema is flattened via allOf, local #/... refs nested within properties, items, additionalProperties, and composition keywords (allOf, anyOf, oneOf, not) must be rewritten to include the remote component path. Without this, generated Go code references unqualified types that don't exist in the local package. Extracts ref-rewriting into a recursive propagateRemoteRefs helper and extends it to walk the full schema tree. Fixes https://github.com/oapi-codegen/oapi-codegen/issues/2288 Co-authored-by: Claude Opus 4.6 (1M context) --- .../externalref/packageA/externalref.gen.go | 23 ++++++- internal/test/externalref/packageA/spec.yaml | 21 ++++++- .../externalref/packageB/externalref.gen.go | 61 ++++++++++++++++++- internal/test/externalref/packageB/spec.yaml | 28 +++++++++ pkg/codegen/merge_schemas.go | 49 ++++++++++++++- 5 files changed, 174 insertions(+), 8 deletions(-) diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go index 582588326c..a859c18af1 100644 --- a/internal/test/externalref/packageA/externalref.gen.go +++ b/internal/test/externalref/packageA/externalref.gen.go @@ -16,18 +16,35 @@ 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"` } +// StatusPostPayload defines model for StatusPostPayload. +type StatusPostPayload struct { + Reason *string `json:"reason,omitempty"` + Status externalRef0.StatusEnum `json:"status"` +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/4yOMcrDMAxG7/L9/xjI7q25QI8QHKMkbhNZ2OpQgu5e7BS6dOikBw896UBIuyQm1gJ3", - "oISVdt/wOt0o6KWi5CSUNVIT7HeqU59CcCiaIy+wDqltjFOV/5lmOPz1n37/jvfiw90vNIxFKIznnQFm", - "1uG7+vUFa43Ic4Ljx7Z1SELsJcIBNa5rOY29AgAA//84dUj5+QAAAA==", + "H4sIAAAAAAAC/5xTzW7CMAx+F2/HSIhrbkPiDNo0LghVJnEhW5pkSToNVXn3KaEIKjqp7GbX9tfvp+1A", + "2MZZQyYG4B0EcaQGS7k0XokjyfdAPveo9aoGvu3g2VMNHJ5m19tZfzhzKD7xQIsqOBJVuU2sA+etIx8V", + "FWj6iR6rWpGWuY0nR8AhRK/MAVJilyd2/0EiQtolBqtSv+T9IZjBhkZQWH9d7fNwOuXzexaQMo+3iLEN", + "axviGk/aovyvEWegzXzEDE8YrJnswzjbqa6kO4RXq8simbYBvgWUjTLAoM3R7di9rWPCluX4BkRE9U3A", + "QJm+nIq0mQ8tHqoKZeexQG8YZvWevlrlSWaaPdxugtGXv2DIR8nRL89b3c8jNQ/SLXlco0fv8ZT7nMdf", + "oQ5VKQk36/fi8r4ytQVuWq0ZWEcGnQIOkFXHYzhP0m8AAAD//1KVtScdBAAA", } // GetSwagger returns the content of the embedded swagger specification file 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..8b07f571c9 100644 --- a/internal/test/externalref/packageB/externalref.gen.go +++ b/internal/test/externalref/packageB/externalref.gen.go @@ -15,16 +15,73 @@ 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"` } +// 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"` +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/yTJwQ0CMQxE0V7mnApypAFqCNHAGm1sKzYHtNreUZa5zJfegW7DTakZqAeibxztyvvj", - "zZ63lT7NOVN4gbbB9fl1oiJyir5wrhWIPg1VP/teYE5tLqhAgbfc4i/nLwAA//8neaWPdgAAAA==", + "H4sIAAAAAAAC/4RRTUvDQBT8L6PHheB1j4LngqKX0sOavNiV/XL3rVDK/nd5a7CxtXjKhJnJm5kcMUaf", + "YqDABfqIMu7Jmw43r+808r3AlGOizJY6EYwnefIhETQKZxve0FpTeIyuUxSqh97CTN4GKNRCGTt1blF4", + "YsO1PHT5yjay/SQo2LDA696XO3Ea5zYz9PY8a+kaQbeZZmjcDKfCw9J2WKWQFpk+qs00SZTlA6f7sc+C", + "tmsKz1LrYh87/bGOQo5u4Zn8v5H6ku3nqsnZHORdlrz2A34ntxNW8ssCordhjtChOqcQEwWTLDSgkAzv", + "yzfTvgIAAP//mT+m2CQCAAA=", } // GetSwagger returns the content of the embedded swagger specification file 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/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go index bc887cfa3b..3becb5e412 100644 --- a/pkg/codegen/merge_schemas.go +++ b/pkg/codegen/merge_schemas.go @@ -168,14 +168,59 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) { } remoteComponent := pathParts[0] + 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, seenSchemaRef map[string]bool) (openapi3.Schema, error) { From eff4a2be5c61df2decf16c4ac14afe8f976a1d5b Mon Sep 17 00:00:00 2001 From: Peter Turi Date: Thu, 30 Apr 2026 01:17:01 +0200 Subject: [PATCH 253/293] fix: allow x-go-type and x-go-type-skip-optional-pointer for allOf (#1610) * fix: allow x-go-type and x-go-type-skip-optional-pointer for allOf This patch ensures that if a schema is defined using allOf the main schema entry's x-go-type and x-go-type-skip-optional-pointer values are considered instead of a random allOf member's. * Add unit tests * update PR for upstream changes Address greptile review feedback and adapt to upstream main: - pkg/codegen/schema.go: simplify the allOf branch. Upstream main now catches x-go-type at the schema level via the combined extensions early return, so the PR's allOf-specific x-go-type override block is unreachable; remove it. Keep x-go-type-skip-optional-pointer propagation as a conditional override (only when the parent sets it explicitly), which preserves the decorator-idiom behavior MergeSchemas relies on for issue #1957. Read from combined extensions for parity with the rest of GenerateGoSchema. - pkg/codegen/test_specs/x-go-type-pet-allof.yaml: add trailing newline. --------- Co-authored-by: Jamie Tanna Co-authored-by: Marcin Romaszewicz Co-authored-by: Marcin Romaszewicz --- pkg/codegen/codegen_test.go | 35 ++++++++++++ pkg/codegen/schema.go | 9 +++ .../test_specs/x-go-type-pet-allof.yaml | 56 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 pkg/codegen/test_specs/x-go-type-pet-allof.yaml diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index b7b3184c3c..037c9e1886 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -173,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") diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 499a36c390..4c6fc4517d 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -394,6 +394,15 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { return Schema{}, fmt.Errorf("error merging schemas: %w", err) } mergedSchema.OAPISchema = schema + // 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 } 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 From 81b9d9525dacf7ac2dd63c1a6cd44903d21a0370 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 18:30:01 -0700 Subject: [PATCH 254/293] Overhaul anonymous schema hoisting (#2348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING: this rename affects generated type names for inline `oneOf`, `anyOf`, and `additionalProperties` response schemas. Two prior name patterns are gone and folded into one canonical form: GetPets_200_Data_Item → GetPets200JSONResponseBody_Data_Item GetPets200JSONResponse_Data_Item → GetPets200JSONResponseBody_Data_Item The pre-existing types had no As/From/Merge accessors and the response roots were anonymous structs that could not be method-bound — that's the bug being fixed (oapi-codegen issues #1900 and #1496). User code referencing the old names could only have done so via reflection or json.RawMessage round-trips, since the types were practically unusable. The documented workaround (hoist to `#/components/schemas/` and `$ref` it) sidesteps this surface entirely, so users who hit the bug and switched to the workaround see no name change. Component schema names, `Params`, request body types, the strict envelope name `Response`, and the client-with-responses envelope name `Response` are all stable. Inline `oneOf`/`anyOf` schemas at any operation root or nested below previously bypassed the union-accessor / additionalProperties boilerplate passes, leaving generated wrapper types method-less (or, for response roots, anonymous structs that no method could be attached to). This change unifies the boilerplate-emission pipeline so every schema root — components, parameters, request bodies, response bodies — gets the same method-emitting passes. Codegen pipeline: - GenerateTypeDefinitions now builds two slices. allTypes stays components-only and feeds GenerateTypes (typedef.tmpl). boilerplateTypes is the wider set — components plus op.TypeDefinitions plus each ResponseTypeDefinition's AdditionalTypeDefinitions — and feeds the method-emitting passes (enum scanning, additionalProperties marshalers, union accessors, union+additionalProperties combined). Operation-derived types now get the same method emission as components, while declarations stay in their per-context templates. - GenerateResponseDefinitions hoists inline response-root schemas with UnionElements / HasAdditionalProperties to a synthetic TypeDefinition named ResponseBody. The strict envelope keeps its Response name and references the body type from inside (struct envelope) or as an alias (no-headers case). Two distinct names so the strict envelope never self-references. - GetResponseTypeDefinitions (client-with-responses path) computes the same body name and points the JSON field at it. - Multi-content-type disambiguation generalized: the responseTypeName itself includes the content-type tag, so separate JSON/XML/YAML content types in the same response naturally produce distinct names. New isMediaTypeSupported helper hardcodes today's expectations (intended to be user-configurable in a future change). - GenerateBodyDefinitions and GetResponseTypeDefinitions skip the local hoist when the operation came from an externally-ref'd path item — the imported package already declared the same hoisted type (PathToTypeName is deterministic), so the schema's RefType is set to externalPkg. instead. Avoids the AsExternalRef0Foo accessor names that would otherwise appear in the importing package. - New OperationDefinition.PathItemRef carries the path item ref through to GetResponseTypeDefinitions; GenerateBodyDefinitions and GenerateResponseDefinitions take it as an explicit parameter for symmetry. - ensureExternalRefsInSchema also patches UnionElements with the imported package qualifier when the enclosing schema came from an external file. - Schema.HasCustomMarshalJSON returns true for inline-but-external union shapes. The strict envelope is rendered as a defined type (`type X externalRef0.Y`), so methods on Y don't transfer; the delegator emitted by the strict template (which calls externalRef0.Y(t).MarshalJSON()) is needed for the response to serialize the union payload instead of the empty struct value. - GenerateUnionBoilerplate and GenerateUnionAndAdditionalProopertiesBoilerplate dedup by TypeName, matching the pre-existing pattern in GenerateAdditionalPropertyBoilerplate. Templates: - client-with-responses.tmpl no longer emits AdditionalTypeDefinitions declarations inline. Those nested response types now flow through op.TypeDefinitions (collected in GenerateTypeDefsForOperation by upstream PR #2284) and get declared once via param-types.tmpl with union/additionalProperties accessor methods attached. - strict-server templates (strict-interface.tmpl, strict-fiber-interface.tmpl, strict-iris-interface.tmpl) encode the response body without touching the unexported union field when the schema is from an external package — the type's MarshalJSON delegator handles it instead. Tests: - New internal/test/anonymous_inner_hoisting fixture exercises As/From/Merge round-trips on every shape: response root oneOf, response root anyOf, response items oneOf, deeply nested oneOf, request body root oneOf, request body property oneOf, plus a cross-branch Merge test. - New internal/test/issues/issue-1378/fooservice_test.go TestExternalRefUnionResponseSerialization locks in the cross-package union response serialization fix; without the HasCustomMarshalJSON change it produces `{}` instead of the union payload. Generated fixtures across internal/test and examples regenerated to reflect the new method emission and naming. Two follow-up cleanups in the strict-server templates were identified during review and deferred — extracting the .union-vs-MarshalJSON access decision into a Go-side EncodeAccessor helper, and pre-computing the full strict envelope declaration line in Go. Both are notes, not blockers. Issue #2010 (cross-module strict-server type embedding) is adjacent but a separate fix surface. Co-authored-by: Claude Opus 4.7 (1M context) --- .../test/anonymous_inner_hoisting/cfg.yaml | 5 + .../anonymous_inner_hoisting/client.gen.go | 1320 +++++++++++++++++ .../anonymous_inner_hoisting/client_test.go | 141 ++ .../test/anonymous_inner_hoisting/generate.go | 3 + .../test/anonymous_inner_hoisting/spec.yaml | 132 ++ .../test/any_of/codegen/inline/openapi.gen.go | 100 +- internal/test/components/components.gen.go | 162 +- .../issues/issue-1277/content-array.gen.go | 31 +- .../issue-1378/bionicle/bionicle.gen.go | 45 +- .../issue-1378/fooservice/fooservice.gen.go | 12 +- .../issue-1378/fooservice/fooservice_test.go | 27 + .../name_conflict_resolution.gen.go | 20 +- internal/test/strict-server/chi/server.gen.go | 4 +- internal/test/strict-server/chi/types.gen.go | 77 +- .../test/strict-server/client/client.gen.go | 80 +- .../test/strict-server/echo/server.gen.go | 4 +- internal/test/strict-server/echo/types.gen.go | 77 +- .../test/strict-server/fiber/server.gen.go | 5 +- .../test/strict-server/fiber/types.gen.go | 77 +- internal/test/strict-server/gin/server.gen.go | 4 +- internal/test/strict-server/gin/types.gen.go | 77 +- .../test/strict-server/gorilla/server.gen.go | 4 +- .../test/strict-server/gorilla/types.gen.go | 77 +- .../test/strict-server/iris/server.gen.go | 5 +- internal/test/strict-server/iris/types.gen.go | 77 +- .../test/strict-server/stdhttp/server.gen.go | 4 +- .../test/strict-server/stdhttp/types.gen.go | 77 +- pkg/codegen/codegen.go | 47 +- pkg/codegen/externalref.go | 35 +- pkg/codegen/operations.go | 182 ++- pkg/codegen/schema.go | 16 +- pkg/codegen/template_helpers.go | 22 + .../templates/client-with-responses.tmpl | 6 - .../strict/strict-fiber-interface.tmpl | 2 +- .../templates/strict/strict-interface.tmpl | 2 +- .../strict/strict-iris-interface.tmpl | 2 +- 36 files changed, 2690 insertions(+), 271 deletions(-) create mode 100644 internal/test/anonymous_inner_hoisting/cfg.yaml create mode 100644 internal/test/anonymous_inner_hoisting/client.gen.go create mode 100644 internal/test/anonymous_inner_hoisting/client_test.go create mode 100644 internal/test/anonymous_inner_hoisting/generate.go create mode 100644 internal/test/anonymous_inner_hoisting/spec.yaml create mode 100644 internal/test/issues/issue-1378/fooservice/fooservice_test.go 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..74fe6907c2 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/client.gen.go @@ -0,0 +1,1320 @@ +// 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 +} + +// 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 +} + +// 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"` + } +} + +// 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"` + } +} + +// 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 +} + +// 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 +} + +// 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/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index 3e9467cb7f..fff0ef0f89 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/labstack/echo/v4" + "github.com/oapi-codegen/runtime" ) const ( @@ -48,11 +49,99 @@ type Rat struct { // apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme type apiKeyAuthContextKey string -// GetPets200JSONResponse_Data_Item defines parameters for GetPets. -type GetPets200JSONResponse_Data_Item struct { +// 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 @@ -220,12 +309,9 @@ type GetPetsResponse struct { Body []byte HTTPResponse *http.Response JSON200 *struct { - Data *[]GetPets_200_Data_Item `json:"data,omitempty"` + Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"` } } -type GetPets_200_Data_Item struct { - union json.RawMessage -} // Status returns HTTPResponse.Status func (r GetPetsResponse) Status() string { @@ -276,7 +362,7 @@ func ParseGetPetsResponse(rsp *http.Response) (*GetPetsResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: var dest struct { - Data *[]GetPets_200_Data_Item `json:"data,omitempty"` + Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"` } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index e8550c87b3..c80b28dc4d 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -587,87 +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) - - 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) -} - // 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) { @@ -990,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/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index fee7e80abb..4e13565987 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -16,32 +16,32 @@ import ( "github.com/go-chi/chi/v5" ) -// Test200JSONResponse_Item defines parameters for Test. -type Test200JSONResponse_Item struct { +// 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 Test200JSONResponse_Item. Returns the specified +// Getter for additional properties for Test200JSONResponseBody_Item. Returns the specified // element and whether it was found -func (a Test200JSONResponse_Item) Get(fieldName string) (value interface{}, found bool) { +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 Test200JSONResponse_Item -func (a *Test200JSONResponse_Item) Set(fieldName string, value interface{}) { +// 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 Test200JSONResponse_Item to handle AdditionalProperties -func (a *Test200JSONResponse_Item) UnmarshalJSON(b []byte) error { +// 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 { @@ -78,8 +78,8 @@ func (a *Test200JSONResponse_Item) UnmarshalJSON(b []byte) error { return nil } -// Override default JSON handling for Test200JSONResponse_Item to handle AdditionalProperties -func (a Test200JSONResponse_Item) MarshalJSON() ([]byte, error) { +// 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) @@ -272,12 +272,7 @@ type ClientWithResponsesInterface interface { type TestResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]Test_200_Item -} -type Test_200_Item struct { - Field1 *string `json:"field1,omitempty"` - Field2 *string `json:"field2,omitempty"` - AdditionalProperties map[string]interface{} `json:"-"` + JSON200 *[]Test200JSONResponseBody_Item } // Status returns HTTPResponse.Status @@ -328,7 +323,7 @@ func ParseTestResponse(rsp *http.Response) (*TestResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []Test_200_Item + var dest []Test200JSONResponseBody_Item if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -505,7 +500,7 @@ type TestResponseObject interface { VisitTestResponse(w http.ResponseWriter) error } -type Test200JSONResponse []Test200JSONResponse_Item +type Test200JSONResponse []Test200JSONResponseBody_Item func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index f708015ae6..c9c57df5fb 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -29,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 { @@ -211,9 +252,7 @@ func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w ht return err } -type GetBionicleName400JSONResponse struct { - union json.RawMessage -} +type GetBionicleName400JSONResponse = GetBionicleName400JSONResponseBody func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index 9c856f981b..b11772fd3c 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -204,14 +204,20 @@ func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w ht return err } -type GetBionicleName400JSONResponse struct { - union json.RawMessage +type GetBionicleName400JSONResponse externalRef0.GetBionicleName400JSONResponseBody + +func (t GetBionicleName400JSONResponse) MarshalJSON() ([]byte, error) { + return externalRef0.GetBionicleName400JSONResponseBody(t).MarshalJSON() +} + +func (t *GetBionicleName400JSONResponse) UnmarshalJSON(b []byte) error { + return (*externalRef0.GetBionicleName400JSONResponseBody)(t).UnmarshalJSON(b) } func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.union); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") 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/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index 348bcff460..b97ae67fa3 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -258,17 +258,17 @@ type QueryJSONBody struct { Q *string `json:"q,omitempty"` } -// PatchResource200ApplicationJSONPatchPlusJSONResponse1 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchPlusJSONResponse1 = []Resource +// PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 = []Resource -// PatchResource200ApplicationJSONPatchPlusJSONResponse2 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchPlusJSONResponse2 = string +// PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 = string -// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 = []Resource +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 = []Resource -// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 = string +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 = string // PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. type PostFooJSONRequestBody PostFooJSONBody @@ -2308,10 +2308,6 @@ type PatchResourceResponse struct { ApplicationjsonPatchQueryJSON200 *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON ApplicationmergePatchJSON200 *N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON } -type PatchResource200ApplicationJSONPatchPlusJSON1 = []Resource -type PatchResource200ApplicationJSONPatchPlusJSON2 = string -type PatchResource200ApplicationJSONPatchQueryPlusJSON1 = []Resource -type PatchResource200ApplicationJSONPatchQueryPlusJSON2 = string // Status returns HTTPResponse.Status func (r PatchResourceResponse) Status() string { diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index caf622b4b2..24563e498f 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -1184,9 +1184,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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 5efe7502b1..d4cdfbc074 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -39,8 +39,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -84,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 @@ -1572,11 +1639,8 @@ type UnionExampleResponse struct { Body []byte HTTPResponse *http.Response ApplicationalternativeJSON200 *Example - JSON200 *struct { - union json.RawMessage - } + JSON200 *UnionExample200JSONResponseBody } -type UnionExample2000 = string // Status returns HTTPResponse.Status func (r UnionExampleResponse) Status() string { @@ -2099,9 +2163,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 3a314fb909..041e8f75d1 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -904,9 +904,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index bdb00bfcdb..caea58b285 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -8,7 +8,6 @@ import ( "compress/gzip" "context" "encoding/base64" - "encoding/json" "errors" "fmt" "io" @@ -1010,9 +1009,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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 00ea144ab2..0642639e37 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -979,9 +979,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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 2c28c12eb4..85fc6fe3a9 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -1095,9 +1095,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/gorilla/types.gen.go b/internal/test/strict-server/gorilla/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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 66d0dce0bb..6bef496890 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -8,7 +8,6 @@ import ( "compress/gzip" "context" "encoding/base64" - "encoding/json" "errors" "fmt" "io" @@ -844,9 +843,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/iris/types.gen.go b/internal/test/strict-server/iris/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index ac8d245c8d..adca621779 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -1090,9 +1090,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/stdhttp/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go index 532c5ebae3..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"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// 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 @@ -70,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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 8514ef83e1..fb588dcfa5 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -345,7 +345,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) } @@ -580,13 +580,28 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op allTypes = append(allTypes, securitySchemeTypes...) } - // 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 + // 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) @@ -594,7 +609,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) } @@ -604,17 +619,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) } @@ -1120,7 +1135,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) } @@ -1141,7 +1161,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) } 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/operations.go b/pkg/codegen/operations.go index 0fedc32be2..4087d30fec 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -329,6 +329,7 @@ type OperationDefinition struct { 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 @@ -401,10 +402,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++ } } @@ -413,57 +414,64 @@ 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 { - // When a response has multiple JSON content types (e.g., - // application/json, application/json-patch+json, and - // application/merge-patch+json), we include a content-type-derived - // segment in the schema path. This is necessary because - // GenerateGoSchema uses the path to name any inline types it - // creates (e.g., oneOf union members). Without the content type - // in the path, all content types for the same response produce - // identically-named inline types. If those content types have - // different schemas, the result is conflicting type declarations; - // if they have the same schema, the result is duplicate - // declarations. Both cases produce code that won't compile. - // - // 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{o.OperationId, responseName} - if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) && globalState.options.OutputOptions.ResolveTypeNameCollisions { - schemaPath = append(schemaPath, mediaTypeToCamelCase(contentTypeName)) - } - 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) - } - - var typeName string + var typeName, tag string switch { // HAL+JSON: case slices.Contains(contentTypesHalJSON, contentTypeName): typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName)) + tag = "HALJSON" case contentTypeName == "application/json": // if it's the standard application/json typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName)) + tag = "JSON" // Vendored JSON 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 slices.Contains(contentTypesYAML, contentTypeName): typeName = fmt.Sprintf("YAML%s", nameNormalizer(responseName)) + tag = "YAML" // XML: 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, @@ -478,7 +486,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini if err != nil { return nil, fmt.Errorf("error dereferencing response Ref: %w", err) } - if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) { + if supportedCount > 1 { if resolved := resolvedNameForRefPath(responseRef.Ref, contentTypeName); resolved != "" { refType = resolved + mediaTypeToCamelCase(contentTypeName) } else { @@ -808,14 +816,14 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { return nil, err } - bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(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(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) } @@ -838,6 +846,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { TypeDefinitions: typeDefinitions, IsAlias: isAlias, AliasTarget: aliasTarget, + PathItemRef: pathItem.Ref, } // check for overrides of SecurityDefinitions. @@ -887,7 +896,14 @@ func generateDefaultOperationID(opName string, requestPath string) (string, erro // 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 } @@ -942,24 +958,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{ @@ -986,7 +1009,9 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody 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{}) @@ -1023,11 +1048,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, @@ -1157,7 +1215,6 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { s.Properties = append(s.Properties, prop) } - s.Description = op.Spec.Description s.GoType = GenStructFromSchema(s) td := TypeDefinition{ @@ -1180,25 +1237,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) } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 4c6fc4517d..bf46a67a63 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -71,16 +71,22 @@ func (s Schema) IsExternalRef() bool { // MarshalJSON/UnmarshalJSON that we need to delegate to. This is true when // the schema is a $ref to a oneOf/anyOf union defined elsewhere. // -// It is deliberately false for inline unions: 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 *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 false + return s.IsExternalRef() } return len(s.OAPISchema.OneOf) > 0 || len(s.OAPISchema.AnyOf) > 0 } diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 3ea88718bb..1beaba0b3f 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -47,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 diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index 8b5b670be6..68ad3d4355 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -53,12 +53,6 @@ type {{genResponseTypeName $opid | ucFirst}} struct { {{- end}} } -{{- range $responseTypeDefinitions}} - {{- range .AdditionalTypeDefinitions}} - type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}} - {{- end}} -{{- end}} - // Status returns HTTPResponse.Status func (r {{genResponseTypeName $opid | ucFirst}}) Status() string { if r.HTTPResponse != nil { diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index bcf372a35c..5f79c84348 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -97,7 +97,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 diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index f722f51a91..25e7455081 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -88,7 +88,7 @@ {{if .IsJSON -}} {{$hasUnionElements := ne 0 (len .Schema.UnionElements) -}} var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}}); err != nil { + 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}}) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 75b1d792ec..32d319ed8d 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -99,7 +99,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 From 218effec236f7f8a8dd8cfb424c7fb07756dc639 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 21:10:52 -0700 Subject: [PATCH 255/293] Synchronize strict servers (#2350) Bring the fiber and iris strict-server interface templates back into parity with the canonical stdhttp template (`strict-interface.tmpl`). Four pieces of drift were addressed: 1. Nullable / optional response-header serialization. Both templates now use the same three-way switch on `.IsNullable` / `.IsOptional` / default that PR #2301 introduced for stdhttp, so unspecified nullable values and nil optional pointers are skipped instead of being stringified into the wire header. 2. Response-header struct field types. The `{{$opid}}{{$statusCode}}ResponseHeaders` struct now uses `{{.GoTypeDef}}` (pointer/nullable-aware) rather than the raw `{{.Schema.TypeDecl}}`, matching the type that the typed-body Visit function expects. 3. `$ref` Text responses. The fixed-status-code + ref branch now matches Multipart and Text together (PR #2225), so `$ref` text responses alias directly to the component response type. Iris additionally drops its unconditional `type X string` short-circuit, which previously masked `$ref`, `$hasHeaders`, and `$fixedStatusCode` for any text response. 4. `$ref` name qualification (fiber only). Switch from `ucFirst` to `ucFirstWithPkgName` so external-ref response types carry their package qualifier, matching stdhttp and iris. Regenerated fixtures under `internal/test/strict-server/{fiber,iris}/server.gen.go` demonstrate the change for items (1) and (2); items (3) and (4) have no existing fiber/iris fixture coverage. The no-content `Visit*Response` branch still renders headers unconditionally in all three templates (including stdhttp); that gap is tracked separately (#2349) and not addressed here. Fixes: #2331 Co-authored-by: Claude Opus 4.7 (1M context) --- .../test/strict-server/fiber/server.gen.go | 12 +++++++---- .../test/strict-server/iris/server.gen.go | 12 +++++++---- .../strict/strict-fiber-interface.tmpl | 18 +++++++++++++---- .../strict/strict-iris-interface.tmpl | 20 +++++++++++++------ 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index caea58b285..71761a1541 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -945,8 +945,8 @@ type HeadersExampleResponseObject interface { type HeadersExample200ResponseHeaders struct { Header1 string Header2 int - NullableHeader string - OptionalHeader string + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -957,8 +957,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)) - ctx.Response().Header.Set("nullable-header", fmt.Sprint(response.Headers.NullableHeader)) - ctx.Response().Header.Set("optional-header", fmt.Sprint(response.Headers.OptionalHeader)) + 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) diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 6bef496890..5d2dce3b6c 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -779,8 +779,8 @@ type HeadersExampleResponseObject interface { type HeadersExample200ResponseHeaders struct { Header1 string Header2 int - NullableHeader string - OptionalHeader string + NullableHeader *string + OptionalHeader *string } type HeadersExample200JSONResponse struct { @@ -791,8 +791,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)) - ctx.ResponseWriter().Header().Set("nullable-header", fmt.Sprint(response.Headers.NullableHeader)) - ctx.ResponseWriter().Header().Set("optional-header", fmt.Sprint(response.Headers.OptionalHeader)) + 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) diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index 5f79c84348..9ff692e814 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -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,7 +40,7 @@ {{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}} } @@ -82,7 +82,17 @@ 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()) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 32d319ed8d..0594e5993a 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -32,17 +32,15 @@ {{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}} } @@ -84,7 +82,17 @@ 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()) From 3338f939f211e618162b8dce75c88155e144bcb4 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Wed, 29 Apr 2026 21:26:48 -0700 Subject: [PATCH 256/293] Strict server: gate no-content response headers on nullable/optional (#2351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The no-content branch of the three strict-server interface templates (`strict-interface.tmpl`, `strict-fiber-interface.tmpl`, `strict-iris-interface.tmpl`) was rendering response headers unconditionally, missing the three-way `.IsNullable` / `.IsOptional` / default switch that PR #2301 added to the typed-body branch. Because the `{{$opid}}{{$statusCode}}ResponseHeaders` struct is shared between the typed-body and no-content branches and uses `{{.GoTypeDef}}` (since #2301 / #2331), an unset optional header field is `*string(nil)` and an unspecified nullable header is a zero `runtime.Nullable[T]`. The bare `fmt.Sprint(...)` in the no-content branch was therefore stringifying these to `` / a typed zero-value and emitting a junk header rather than omitting it. A 204-style response declaring an optional or nullable header — with the caller leaving it unset — produced a wrong header value instead of no header at all. Apply the same three-way switch to the no-content branch in all three templates so unset values are skipped, matching the typed-body branch behavior and matching what callers expect for OpenAPI `required: false` / `nullable: true` response headers. Add regression coverage: - `strict-schema.yaml` gains a `/no-content-headers` POST operation whose only response is 204 with `optional-header` (`required: false`) and `nullable-header` (`nullable: true`). - `NoContentHeaders` handler stub returning an empty `NoContentHeaders204Response{}` is wired into all seven framework server implementations (chi, echo, fiber, gin, gorilla, iris, stdhttp). - `NoContentHeadersOmitUnset` subtest added to the three `testImpl` copies (shared, stdhttp, fiber). Asserts both headers are absent from `rr.Header().Values(...)` when the response struct's header fields are left at their zero values. The shared `testImpl` covers chi, echo, gin, and iris in one place; stdhttp and fiber maintain their own copies because they live in separate test files (stdhttp because of its own go.mod, fiber because of its package boundary). Gorilla generates code but has no test driver — the handler stub is still required so the generated `StrictServerInterface` is satisfied. Fixes: #2349 Co-authored-by: Claude Opus 4.7 (1M context) --- internal/test/strict-server/chi/server.gen.go | 120 +++++++++++++++--- internal/test/strict-server/chi/server.go | 4 + .../test/strict-server/client/client.gen.go | 99 +++++++++++++++ .../test/strict-server/echo/server.gen.go | 107 +++++++++++++--- internal/test/strict-server/echo/server.go | 4 + .../strict-server/fiber/fiber_strict_test.go | 6 + .../test/strict-server/fiber/server.gen.go | 119 ++++++++++++++--- internal/test/strict-server/fiber/server.go | 4 + internal/test/strict-server/gin/server.gen.go | 112 +++++++++++++--- internal/test/strict-server/gin/server.go | 4 + .../test/strict-server/gorilla/server.gen.go | 114 ++++++++++++++--- internal/test/strict-server/gorilla/server.go | 4 + .../test/strict-server/iris/server.gen.go | 109 +++++++++++++--- internal/test/strict-server/iris/server.go | 4 + .../test/strict-server/stdhttp/server.gen.go | 113 ++++++++++++++--- internal/test/strict-server/stdhttp/server.go | 4 + .../strict-server/stdhttp/std_strict_test.go | 6 + .../test/strict-server/strict-schema.yaml | 16 +++ internal/test/strict-server/strict_test.go | 6 + .../strict/strict-fiber-interface.tmpl | 12 +- .../templates/strict/strict-interface.tmpl | 12 +- .../strict/strict-iris-interface.tmpl | 12 +- 22 files changed, 848 insertions(+), 143 deletions(-) diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index 24563e498f..cbf2515358 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -39,6 +39,9 @@ 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) @@ -94,6 +97,11 @@ 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) @@ -209,6 +217,20 @@ 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) { @@ -536,6 +558,9 @@ 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) }) @@ -783,6 +808,33 @@ 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 } @@ -1233,6 +1285,9 @@ 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) @@ -1463,6 +1518,30 @@ 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 @@ -1782,26 +1861,27 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go index 914f967268..1f4c633fae 100644 --- a/internal/test/strict-server/chi/server.go +++ b/internal/test/strict-server/chi/server.go @@ -122,6 +122,10 @@ 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 } diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index d4cdfbc074..e9888963f1 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -244,6 +244,9 @@ 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) @@ -385,6 +388,18 @@ 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 { @@ -749,6 +764,33 @@ func NewMultipleRequestAndResponseTypesRequestWithBody(server string, contentTyp 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 @@ -1208,6 +1250,9 @@ 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) @@ -1371,6 +1416,35 @@ func (r MultipleRequestAndResponseTypesResponse) ContentType() string { return "" } +type NoContentHeadersResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// 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 @@ -1734,6 +1808,15 @@ 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...) @@ -1967,6 +2050,22 @@ 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) diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 041e8f75d1..be6d0687fc 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -39,6 +39,9 @@ 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 @@ -111,6 +114,15 @@ 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 @@ -277,6 +289,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/multipart", wrapper.MultipartExample) router.POST(baseURL+"/multipart-related", wrapper.MultipartRelatedExample) router.POST(baseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes) + router.POST(baseURL+"/no-content-headers", wrapper.NoContentHeaders) router.POST(baseURL+"/required-json-body", wrapper.RequiredJSONBody) router.POST(baseURL+"/required-text-body", wrapper.RequiredTextBody) router.GET(baseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters) @@ -503,6 +516,33 @@ 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 } @@ -953,6 +993,9 @@ 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) @@ -1153,6 +1196,29 @@ 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 @@ -1455,26 +1521,27 @@ func (sh *strictHandler) UnionExample(ctx echo.Context) error { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go index 914f967268..1f4c633fae 100644 --- a/internal/test/strict-server/echo/server.go +++ b/internal/test/strict-server/echo/server.go @@ -122,6 +122,10 @@ 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 } diff --git a/internal/test/strict-server/fiber/fiber_strict_test.go b/internal/test/strict-server/fiber/fiber_strict_test.go index cb8b509b08..473aa394f8 100644 --- a/internal/test/strict-server/fiber/fiber_strict_test.go +++ b/internal/test/strict-server/fiber/fiber_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/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index 71761a1541..9b887e72ae 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -38,6 +38,9 @@ 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 @@ -150,6 +153,24 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) 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 { @@ -417,6 +438,8 @@ 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) @@ -637,6 +660,33 @@ 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 } @@ -1057,6 +1107,9 @@ 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) @@ -1251,6 +1304,31 @@ 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 @@ -1563,26 +1641,27 @@ func (sh *strictHandler) UnionExample(ctx *fiber.Ctx) error { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go index 914f967268..1f4c633fae 100644 --- a/internal/test/strict-server/fiber/server.go +++ b/internal/test/strict-server/fiber/server.go @@ -122,6 +122,10 @@ 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 } diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 0642639e37..076105a01a 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -39,6 +39,9 @@ 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) @@ -131,6 +134,19 @@ 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) { @@ -353,6 +369,7 @@ 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) @@ -578,6 +595,33 @@ 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 } @@ -1028,6 +1072,9 @@ 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) @@ -1286,6 +1333,30 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) { } } +// 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 @@ -1605,26 +1676,27 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go index 914f967268..1f4c633fae 100644 --- a/internal/test/strict-server/gin/server.go +++ b/internal/test/strict-server/gin/server.go @@ -122,6 +122,10 @@ 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 } diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 85fc6fe3a9..c7ee8ecea4 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -39,6 +39,9 @@ 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) @@ -135,6 +138,20 @@ 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) { @@ -458,6 +475,8 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods(http.MethodPost) + r.HandleFunc(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders).Methods(http.MethodPost) + r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods(http.MethodPost) r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods(http.MethodPost) @@ -694,6 +713,33 @@ 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 } @@ -1144,6 +1190,9 @@ 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) @@ -1374,6 +1423,30 @@ 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 @@ -1693,26 +1766,27 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/gorilla/server.go b/internal/test/strict-server/gorilla/server.go index 2cb801e035..3d3890d982 100644 --- a/internal/test/strict-server/gorilla/server.go +++ b/internal/test/strict-server/gorilla/server.go @@ -98,6 +98,10 @@ 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 } diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 5d2dce3b6c..649d39e2e2 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -38,6 +38,9 @@ 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) @@ -104,6 +107,13 @@ 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) { @@ -259,6 +269,7 @@ 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) @@ -471,6 +482,33 @@ 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 } @@ -891,6 +929,9 @@ 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) @@ -1116,6 +1157,33 @@ 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 @@ -1465,26 +1533,27 @@ func (sh *strictHandler) UnionExample(ctx iris.Context) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/iris/server.go b/internal/test/strict-server/iris/server.go index f87df99759..12b000d733 100644 --- a/internal/test/strict-server/iris/server.go +++ b/internal/test/strict-server/iris/server.go @@ -121,6 +121,10 @@ 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 } diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index adca621779..b3c693a5ba 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -40,6 +40,9 @@ 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) @@ -136,6 +139,20 @@ 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) { @@ -462,6 +479,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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) @@ -689,6 +707,33 @@ 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 } @@ -1139,6 +1184,9 @@ 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) @@ -1369,6 +1417,30 @@ 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 @@ -1688,26 +1760,27 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xZzXLbNhB+FQzaUwqatuOTbo0nk7Zp645snzo+QMRKQgICCLAUrdHo3TsgQP3SjpRK", - "lieTm0TuH75vd7kAZrQwpTUaNHram1EH3hrtofkz4MLBlwo8hn8CfOGkRWk07dF3XPTTuzmjDirPBwpa", - "9SBfGI2gG1VurZIFD6r5Jx/0Z9QXYyh5+PWzgyHt0Z/yZSh5fOtzeOSlVUDn8znbiODmI2V0DFyAa6KN", - "Py/iKr5U0oGgPXQVsBVfOLVAe9Sjk3pEg9GodrmTmtQII3AhmqCaggwCbZy9GbXOWHAoI4YTriro9pye", - "mMEnKDCuUOqh2cb62mjkUnsi5HAIDjSSBC4JNjzxlbXGIQgymJLgoUDiwU3AUUZRYgiM3q4+JylgTxmd", - "gPPR0cXZ+dl54NNY0NxK2qNvm0eMWo7jZkELAq3pyos/bm/+JtITXqEpOcqCKzUlJXd+zBUIIjWaEGJV", - "oD+jjSfXJMbvImm/T1AympLvnRHTYyRUk7cr6X55fv5CeTtn9Co667KxCCpfKcDGzJBXqgPze/1Zm1oT", - "cM64tLK8rBRKyx2ucrWO9l+tyC6QL+zlQ+PKTHDkR0L9UJ5ODXzmQHEM7eSrBPSj5H48rJg/Kgv/x89J", - "OUj9uLNP3Y5N7cnY1AQNEcAVqSWOSau40WClJpx4qUcKSBsU6yRTQfos/qpFP63lLtg4ej9ja1Yes7qu", - "s6aAKqdAF0Z8G4WMypKPILd6tK4ebHOkPTqYYkjZ7Q/cgQqZUYRHzK3icgOYTZcv1NJ/IH2wwo7l2g5e", - "WWAkG6T66C7cVF4kSIVBo9VlxBtSSh+qNL70Y1MpQbiq+dTH/rA9cfSTepg8msI8+tjBNubM73sMWVAb", - "Mus01N7BI36V2j0Sf1/6Xrqm9qeo2ROIbGSyzzCtjROZ5Y6XgOB8PgtxzoOtEXSY/GchSQquyQCI5iUI", - "wocIjnwwJJn0HfxEvx/MxyiyNNVsOBZ/ev/OaACv2YRQRoMD2ov4sT02ew/HpapFM26FszVXTyV8Emmh", - "czD0YSDp4rgDv+ipvyJxmi3T87m5dTjwEkkdmHx68A4tYZdh+4CDx2vvAlV8+DRmSWsX2L5xjtkBxYkU", - "YPLSXu1p+WSgeguFHEoQWVpFFmN7qiVcG104wPUNSPgYaoNkYYwMpgTHQCICzfexBlJWHonl3hOJTRdR", - "Mp4VCdhqHvfLyK6jp7tlO32O1TdH4vTNqRi9Or/YX+XtkfNmbSPxRD32/3wfZfY9MTvYjmXP/dbh/J6o", - "nGuJ42zlyLm7hH+LAstvegFyEiYiLYgDrJwGQSaSt8egW7WZDCxp7ZqFYhjLaag9/t5nIGLP2rqkzx6B", - "P3zHB7Snu1hgVFdKNQNkYmVtSe3L1tK2W9Msg6tO9a7u/DJVU2n53LXBfXhN0kS/+aWSRr/SSwGuEJzm", - "KCfwy2FOk7atGA03w6buN9hjO3p4eH2XZ8fOujmj8Z4rNszKqdDVEG0vz+P92Jmv+WgE7kyanFsZUPov", - "AAD//ysZ4qQMHQAA", + "H4sIAAAAAAAC/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", + "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", + "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", + "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", + "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", + "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", + "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", + "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", + "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", + "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", + "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", + "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", + "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", + "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", + "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", + "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", + "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", + "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", + "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", + "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", + "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/test/strict-server/stdhttp/server.go b/internal/test/strict-server/stdhttp/server.go index 4f39f939cc..3d24a5d272 100644 --- a/internal/test/strict-server/stdhttp/server.go +++ b/internal/test/strict-server/stdhttp/server.go @@ -124,6 +124,10 @@ 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 } 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/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml index ba1a2ffab3..fd5f07feda 100644 --- a/internal/test/strict-server/strict-schema.yaml +++ b/internal/test/strict-server/strict-schema.yaml @@ -215,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 diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go index 03cade9cc9..49a6abe25a 100644 --- a/internal/test/strict-server/strict_test.go +++ b/internal/test/strict-server/strict_test.go @@ -228,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/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index 9ff692e814..baad4ab4e5 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -173,7 +173,17 @@ {{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 diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 25e7455081..39fbc98855 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -212,7 +212,17 @@ {{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 diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 0594e5993a..5d9b5965c0 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -174,7 +174,17 @@ {{end -}} func (response {{$opid}}{{$statusCode}}Response) 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 -}} ctx.StatusCode({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}}) return nil From 036a54b7619b0c1da0e20b960bcd80428dec7980 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 30 Apr 2026 07:12:24 -0700 Subject: [PATCH 257/293] per-operation middleware in Echo (#2353) Closes: #518 Add a RegisterHandlersWithOptions to both Echo backends, which takes a BaseUrl and a map of OperationMiddlewares, keyed by spec OperationId. Only Echo supports registering per-op middleware, so this change is only for Echo. --- .../echo-v5/api/petstore-server.gen.go | 33 ++++-- .../echo/api/petstore-server.gen.go | 41 +++++-- .../test/any_of/codegen/inline/openapi.gen.go | 27 ++++- .../any_of/codegen/ref_schema/openapi.gen.go | 27 ++++- internal/test/filter/operations/server.gen.go | 29 ++++- internal/test/filter/tags/server.gen.go | 29 ++++- internal/test/issues/issue-1180/issue.gen.go | 27 ++++- .../test/issues/issue-1182/pkg1/pkg1.gen.go | 27 ++++- .../test/issues/issue-1182/pkg2/pkg2.gen.go | 25 ++++- .../test/issues/issue-1189/issue1189.gen.go | 27 ++++- .../test/issues/issue-1397/issue1397.gen.go | 27 ++++- .../issue-1529/strict-echo/issue1529.gen.go | 27 ++++- internal/test/issues/issue-312/issue.gen.go | 29 ++++- internal/test/issues/issue-518/config.yaml | 6 + internal/test/issues/issue-518/doc.go | 3 + .../test/issues/issue-518/issue518.gen.go | 106 ++++++++++++++++++ .../test/issues/issue-518/issue518_test.go | 106 ++++++++++++++++++ internal/test/issues/issue-518/spec.yaml | 26 +++++ internal/test/issues/issue-52/issue.gen.go | 27 ++++- .../issue-grab_import_names/issue.gen.go | 27 ++++- .../issue-illegal_enum_names/issue.gen.go | 27 ++++- .../test/parameters/echo/gen/server.gen.go | 79 ++++++++----- internal/test/parameters/echov5/server.gen.go | 79 ++++++++----- internal/test/schemas/schemas.gen.go | 45 +++++--- .../test/strict-server/echo/server.gen.go | 55 ++++++--- pkg/codegen/operations.go | 29 ++++- pkg/codegen/templates/echo/echo-register.tmpl | 27 ++++- .../templates/echo/v5/echo-register.tmpl | 27 ++++- 28 files changed, 864 insertions(+), 180 deletions(-) create mode 100644 internal/test/issues/issue-518/config.yaml create mode 100644 internal/test/issues/issue-518/doc.go create mode 100644 internal/test/issues/issue-518/issue518.gen.go create mode 100644 internal/test/issues/issue-518/issue518_test.go create mode 100644 internal/test/issues/issue-518/spec.yaml diff --git a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go index ac4b6f5270..7dc2404777 100644 --- a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go +++ b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go @@ -121,23 +121,42 @@ type EchoRouter interface { 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) { - 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"]...) } diff --git a/examples/petstore-expanded/echo/api/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go index 8767c17a14..8565fafd5e 100644 --- a/examples/petstore-expanded/echo/api/petstore-server.gen.go +++ b/examples/petstore-expanded/echo/api/petstore-server.gen.go @@ -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,23 +121,42 @@ 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"]...) } diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index fff0ef0f89..c9eeb406b3 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -412,19 +412,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+"/pets", wrapper.GetPets) + router.GET(options.BaseURL+"/pets", wrapper.GetPets, options.OperationMiddlewares["getPets"]...) } diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index 0aa30cd67f..f8dcee8ce4 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -413,19 +413,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+"/pets", wrapper.GetPets) + router.GET(options.BaseURL+"/pets", wrapper.GetPets, options.OperationMiddlewares["getPets"]...) } 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/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index 37499ca5cc..ffab4accf7 100644 --- a/internal/test/issues/issue-1180/issue.gen.go +++ b/internal/test/issues/issue-1180/issue.gen.go @@ -287,20 +287,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+"/simplePrimitive/:param", wrapper.GetSimplePrimitive) + router.GET(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive, options.OperationMiddlewares["getSimplePrimitive"]...) } diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index 5baac42d25..13cce371bf 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -273,20 +273,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"]...) } diff --git a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go index df4e45e12d..906298efc5 100644 --- a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go +++ b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go @@ -162,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) { } diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index e06d16c824..c13992c9b5 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -495,20 +495,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.Test) + router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["Test"]...) } diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index 81bfad13c2..8d51c9d305 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -358,20 +358,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.Test) + router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["test"]...) } diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index 5356f847bb..7e5a0c7929 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -303,20 +303,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.Test) + router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["test"]...) } diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index 07102f000b..e149b26d44 100644 --- a/internal/test/issues/issue-312/issue.gen.go +++ b/internal/test/issues/issue-312/issue.gen.go @@ -490,21 +490,40 @@ 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"]...) } 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 d79ef78059..07fd1b0a14 100644 --- a/internal/test/issues/issue-52/issue.gen.go +++ b/internal/test/issues/issue-52/issue.gen.go @@ -298,20 +298,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+"/example", wrapper.ExampleGet) + router.GET(options.BaseURL+"/example", wrapper.ExampleGet, options.OperationMiddlewares["exampleGet"]...) } 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 08af8f82ed..32cf049063 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -355,20 +355,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+"/foo", wrapper.GetFoo) + router.GET(options.BaseURL+"/foo", wrapper.GetFoo, options.OperationMiddlewares["GetFoo"]...) } 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 277dc53e3f..11a39afe9e 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -329,20 +329,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+"/foo", wrapper.GetFoo) + router.GET(options.BaseURL+"/foo", wrapper.GetFoo, options.OperationMiddlewares["GetFoo"]...) } diff --git a/internal/test/parameters/echo/gen/server.gen.go b/internal/test/parameters/echo/gen/server.gen.go index c3c6d36d8f..ee44e88832 100644 --- a/internal/test/parameters/echo/gen/server.gen.go +++ b/internal/test/parameters/echo/gen/server.gen.go @@ -834,46 +834,65 @@ 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+"/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+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive) - router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) - router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) - router.GET(baseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive) - router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) - router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) - router.GET(baseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive) - router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) - router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) - router.GET(baseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive) - router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough) - router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject) - router.GET(baseURL+"/queryDelimited", wrapper.GetQueryDelimited) - router.GET(baseURL+"/queryForm", wrapper.GetQueryForm) - router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) - router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) - router.GET(baseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive) - 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) + 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"]...) } diff --git a/internal/test/parameters/echov5/server.gen.go b/internal/test/parameters/echov5/server.gen.go index 748ae76ad1..46a5ed2ad7 100644 --- a/internal/test/parameters/echov5/server.gen.go +++ b/internal/test/parameters/echov5/server.gen.go @@ -834,46 +834,65 @@ type EchoRouter interface { 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) { - 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+"/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+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive) - router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray) - router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject) - router.GET(baseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive) - router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray) - router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject) - router.GET(baseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive) - router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray) - router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject) - router.GET(baseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive) - router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough) - router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject) - router.GET(baseURL+"/queryDelimited", wrapper.GetQueryDelimited) - router.GET(baseURL+"/queryForm", wrapper.GetQueryForm) - router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray) - router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject) - router.GET(baseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive) - 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) + 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"]...) } diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 828428a84a..d47eea4e87 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -1657,29 +1657,48 @@ 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"]...) } diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index be6d0687fc..12172f8336 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -272,34 +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.POST(baseURL+"/no-content-headers", wrapper.NoContentHeaders) - router.POST(baseURL+"/required-json-body", wrapper.RequiredJSONBody) - router.POST(baseURL+"/required-text-body", wrapper.RequiredTextBody) - 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"]...) } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 4087d30fec..94b6911c71 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -313,6 +313,8 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen type OperationDefinition struct { // 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 @@ -342,6 +344,17 @@ func (o *OperationDefinition) HandlerName() string { 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 // are handled differently from the rest, since they're mandatory. func (o *OperationDefinition) Params() []ParameterDefinition { @@ -757,6 +770,11 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { } // 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 operationId == "" { operationId, err = generateDefaultOperationID(opName, requestPath) @@ -831,11 +849,12 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { ensureExternalRefsInResponseDefinitions(&responseDefinitions, pathItem.Ref) opDef := OperationDefinition{ - PathParams: pathParams, - HeaderParams: FilterParameterDefinitionByType(allParams, "header"), - QueryParams: FilterParameterDefinitionByType(allParams, "query"), - CookieParams: FilterParameterDefinitionByType(allParams, "cookie"), - OperationId: nameNormalizer(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, diff --git a/pkg/codegen/templates/echo/echo-register.tmpl b/pkg/codegen/templates/echo/echo-register.tmpl index dcfeb54f18..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.{{.HandlerName}}) +{{range .}}router.{{.Method}}(options.BaseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}, options.OperationMiddlewares["{{.MiddlewareKey}}"]...) {{end}} } diff --git a/pkg/codegen/templates/echo/v5/echo-register.tmpl b/pkg/codegen/templates/echo/v5/echo-register.tmpl index bd0e968b0f..d311fefbe2 100644 --- a/pkg/codegen/templates/echo/v5/echo-register.tmpl +++ b/pkg/codegen/templates/echo/v5/echo-register.tmpl @@ -15,19 +15,38 @@ type EchoRouter interface { 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) { - 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.{{.HandlerName}}) +{{range .}}router.{{.Method}}(options.BaseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}, options.OperationMiddlewares["{{.MiddlewareKey}}"]...) {{end}} } From 9643421365d811bdfa09098204388a1682b2b95d Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 30 Apr 2026 09:36:27 -0700 Subject: [PATCH 258/293] fix example codegen (#2354) * fix example codegen aae687ce8fe987714a5c6ba1e18a704dc4503209 broke example codegen, since the "generate" directory caused the "make generate" rule not to run, since it already existed. It needs to be .PHONY. I'll refactor examples a bit later. * Pin to HEAD pseudo-version --- examples/Makefile | 1 + .../authenticated-api/echo/api/api.gen.go | 49 ++++++++-- examples/client/client.gen.go | 20 +++- examples/clienttypenameclash/client.gen.go | 10 +- .../custom-client-type.gen.go | 10 +- examples/extensions/xenumnames/gen.go | 36 +++++++ examples/go.mod | 2 + .../multiplepackages/admin/server.gen.go | 3 +- .../import-mapping/samepackage/server.gen.go | 18 ++-- examples/minimal-server/echo/api/ping.gen.go | 27 +++++- examples/minimal-server/fiber/api/ping.gen.go | 26 ++++- .../minimal-server/gorillamux/api/ping.gen.go | 2 +- .../stdhttp-go-tool/api/ping.gen.go | 6 +- .../echo/api/api.gen.go | 27 +++++- examples/overlay/api/ping.gen.go | 2 +- .../petstore-expanded/chi/api/petstore.gen.go | 26 +++-- .../fiber/api/petstore-server.gen.go | 75 +++++++++++++-- .../gin/api/petstore-server.gen.go | 11 ++- .../gorilla/api/petstore.gen.go | 34 +++++-- .../iris/api/petstore-server.gen.go | 11 ++- .../petstore-expanded/petstore-client.gen.go | 56 +++++++++-- .../strict/api/petstore-server.gen.go | 94 ++++++++++++++----- .../streaming/client/sse/streaming.gen.go | 8 ++ .../streaming/stdhttp/sse/streaming.gen.go | 5 +- 24 files changed, 453 insertions(+), 106 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 5ec0edd058..41d1778de8 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -4,6 +4,7 @@ lint: lint-ci: $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m +.PHONY: generate generate: go generate ./... diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index 1dc357519f..9cada0501d 100644 --- a/examples/authenticated-api/echo/api/api.gen.go +++ b/examples/authenticated-api/echo/api/api.gen.go @@ -187,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 } @@ -225,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 } @@ -309,6 +309,14 @@ 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 @@ -331,6 +339,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...) @@ -461,21 +477,40 @@ 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"]...) } diff --git a/examples/client/client.gen.go b/examples/client/client.gen.go index 8ef6b78564..786d8c0b10 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 } @@ -248,6 +248,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 @@ -272,6 +280,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/client.gen.go b/examples/clienttypenameclash/client.gen.go index 219a2a0d4d..4ed74d1777 100644 --- a/examples/clienttypenameclash/client.gen.go +++ b/examples/clienttypenameclash/client.gen.go @@ -126,7 +126,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 } @@ -203,6 +203,14 @@ func (r UpdateClientResp) StatusCode() int { 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...) diff --git a/examples/custom-client-type/custom-client-type.gen.go b/examples/custom-client-type/custom-client-type.gen.go index 6dd2ef0195..27f63d8185 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 } @@ -203,6 +203,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/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/go.mod b/examples/go.mod index 547b7aaf10..cb225c3da4 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -126,3 +126,5 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen diff --git a/examples/import-mapping/multiplepackages/admin/server.gen.go b/examples/import-mapping/multiplepackages/admin/server.gen.go index 36e33e4c4c..3235142110 100644 --- a/examples/import-mapping/multiplepackages/admin/server.gen.go +++ b/examples/import-mapping/multiplepackages/admin/server.gen.go @@ -42,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/samepackage/server.gen.go b/examples/import-mapping/samepackage/server.gen.go index bd9445262b..22710b98d8 100644 --- a/examples/import-mapping/samepackage/server.gen.go +++ b/examples/import-mapping/samepackage/server.gen.go @@ -4,6 +4,7 @@ package samepackage import ( + "bytes" "context" "encoding/json" "fmt" @@ -11,7 +12,6 @@ import ( "github.com/go-chi/chi/v5" "github.com/oapi-codegen/runtime" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" openapi_types "github.com/oapi-codegen/runtime/types" ) @@ -45,11 +45,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 @@ -197,10 +198,15 @@ type GetUserByIdResponseObject interface { 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) - - return json.NewEncoder(w).Encode(response) + _, err := buf.WriteTo(w) + return err } // StrictServerInterface represents all server handlers. @@ -210,8 +216,8 @@ type StrictServerInterface interface { GetUserById(ctx context.Context, request GetUserByIdRequestObject) (GetUserByIdResponseObject, 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/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/ping.gen.go b/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go index 794f8d817f..0d4ab7751a 100644 --- a/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go +++ b/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go @@ -119,10 +119,10 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. +// ServeMux is an abstraction of [http.ServeMux]. type ServeMux interface { HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) + http.Handler } type StdHTTPServerOptions struct { @@ -165,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/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/overlay/api/ping.gen.go b/examples/overlay/api/ping.gen.go index d36bdd55b3..757cd1c6b4 100644 --- a/examples/overlay/api/ping.gen.go +++ b/examples/overlay/api/ping.gen.go @@ -165,7 +165,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/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go index 88b246f37b..f599568124 100644 --- a/examples/petstore-expanded/chi/api/petstore.gen.go +++ b/examples/petstore-expanded/chi/api/petstore.gen.go @@ -7,6 +7,7 @@ import ( "bytes" "compress/gzip" "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 diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go index a5c583ef06..c8f2b20b48 100644 --- a/examples/petstore-expanded/fiber/api/petstore-server.gen.go +++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go @@ -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 @@ -68,51 +71,102 @@ func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error { 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, Type: "integer", Format: "int64"}) + 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, Type: "integer", Format: "int64"}) + 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 { diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go index 02499fcc18..52ce7a8087 100644 --- a/examples/petstore-expanded/gin/api/petstore-server.gen.go +++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go @@ -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 diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go index 0ccc7da0b5..dea4e55e54 100644 --- a/examples/petstore-expanded/gorilla/api/petstore.gen.go +++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go @@ -7,6 +7,7 @@ import ( "bytes" "compress/gzip" "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,13 +311,13 @@ 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 } diff --git a/examples/petstore-expanded/iris/api/petstore-server.gen.go b/examples/petstore-expanded/iris/api/petstore-server.gen.go index a559c238d5..9f52757c5c 100644 --- a/examples/petstore-expanded/iris/api/petstore-server.gen.go +++ b/examples/petstore-expanded/iris/api/petstore-server.gen.go @@ -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) diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go index aa35c93ca6..5b5d01d78b 100644 --- a/examples/petstore-expanded/petstore-client.gen.go +++ b/examples/petstore-expanded/petstore-client.gen.go @@ -236,20 +236,24 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e if params.Tags != nil { - if queryFragments, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); 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 { - rawQueryFragments = append(rawQueryFragments, queryFragments) + for _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } } } if params.Limit != nil { - if queryFragments, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); 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 { - rawQueryFragments = append(rawQueryFragments, queryFragments) + for _, qp := range strings.Split(queryFrag, "&") { + rawQueryFragments = append(rawQueryFragments, qp) + } } } @@ -260,7 +264,7 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e 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 } @@ -298,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 } @@ -314,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 } @@ -334,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 } @@ -348,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 } @@ -368,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 } @@ -457,6 +461,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 @@ -480,6 +492,14 @@ 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 @@ -502,6 +522,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 @@ -525,6 +553,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/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go index f1ba3d6d44..4877d1d564 100644 --- a/examples/petstore-expanded/strict/api/petstore-server.gen.go +++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go @@ -9,6 +9,7 @@ import ( "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) diff --git a/examples/streaming/client/sse/streaming.gen.go b/examples/streaming/client/sse/streaming.gen.go index 65a15573ff..d20b2063e3 100644 --- a/examples/streaming/client/sse/streaming.gen.go +++ b/examples/streaming/client/sse/streaming.gen.go @@ -196,6 +196,14 @@ func (r GetStreamResponse) StatusCode() int { 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...) diff --git a/examples/streaming/stdhttp/sse/streaming.gen.go b/examples/streaming/stdhttp/sse/streaming.gen.go index a619348ee0..94aa81e3e4 100644 --- a/examples/streaming/stdhttp/sse/streaming.gen.go +++ b/examples/streaming/stdhttp/sse/streaming.gen.go @@ -18,7 +18,6 @@ import ( "strings" "github.com/getkin/kin-openapi/openapi3" - strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" ) // ServerInterface represents all server handlers. @@ -233,8 +232,8 @@ type StrictServerInterface interface { GetStream(ctx context.Context, request GetStreamRequestObject) (GetStreamResponseObject, 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) From 7517e092e25b19eeba293aa8e88a2b62626a5226 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 30 Apr 2026 11:54:15 -0700 Subject: [PATCH 259/293] respect output file path on gofmt failure (#2356) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `imports.Process` rejected the generated source, `Generate()` discarded the code and stuffed a line-numbered dump of it into the returned error. The CLI then printed that error to stderr and never wrote the requested `-o` (or config `output:`) file, so users saw a huge stderr spew with no output file produced. Return the raw pre-format code from `Generate()` alongside the error, and have the CLI write it to the configured destination before exiting. The error message itself is now a single line referencing the failing source line; users can open the written file to inspect the broken code directly. `addLineNumbers` is dropped — it was only used by the removed in-error code dump. Closes: #2340 --- cmd/oapi-codegen/oapi-codegen.go | 32 +++++++++++++++++++------------- pkg/codegen/codegen.go | 25 ++++--------------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go index 604c0b3f0f..f540a6808a 100644 --- a/cmd/oapi-codegen/oapi-codegen.go +++ b/cmd/oapi-codegen/oapi-codegen.go @@ -320,21 +320,27 @@ func main() { 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) + + // 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) + } } - if opts.OutputFile != "" { - if err := os.MkdirAll(filepath.Dir(opts.OutputFile), 0o755); err != nil { - errExit("error unable to create directory: %s\n", err) - } - err = os.WriteFile(opts.OutputFile, []byte(code), 0o644) - if err != nil { - errExit("error writing generated code to file: %s\n", err) - } - } else { - fmt.Print(code) + if genErr != nil { + errExit("error generating code: %s\n", genErr) } } diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index fb588dcfa5..afb0f0e3db 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -517,34 +517,17 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { outBytes, err := imports.Process(opts.PackageName+".go", []byte(goCode), nil) if err != nil { - // if we don't get a line number errLine := -1 var scanErr scanner.ErrorList if errors.As(err, &scanErr) && scanErr.Len() > 0 { - // for now, only return the first error's information errLine = scanErr[0].Pos.Line } - return "", fmt.Errorf("error formatting Go code:\n%s\nerror was: %w", addLineNumbers(goCode, errLine), err) - } - return string(outBytes), nil -} - -func addLineNumbers(goCode string, lineWithError int) string { - var out []string - lines := strings.Split(goCode, "\n") - for i, line := range lines { - // lines for humans start at 1 - lineNumber := i + 1 - - errLine := " " - if lineNumber == lineWithError { - errLine = "❗" + if errLine > 0 { + return goCode, fmt.Errorf("error formatting Go code at line %d: %w", errLine, err) } - - out = append(out, fmt.Sprintf("%s%5d: %s", errLine, lineNumber, line)) + return goCode, fmt.Errorf("error formatting Go code: %w", err) } - - return strings.Join(out, "\n") + return string(outBytes), nil } func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []OperationDefinition, excludeSchemas []string) (string, error) { From fbc8e0dbb991a4d4c2928fce71400f338ece7228 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 30 Apr 2026 14:36:51 -0700 Subject: [PATCH 260/293] revert external-ref carve-out in strict-server response embedding (#2010) (#2357) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #1387 added an `$isExternalRef` branch to the strict-{,fiber-,iris-} interface templates that strips the `Response` suffix when embedding an external response ref. That made external refs to a `components/responses/...` resolve to the bare schema name (`N400`) instead of the strict envelope (`N400JSONResponse`). The result: when spec A and spec B both generate strict-server and A $refs B's response component, A's local envelope embeds `N400JSONResponse` while A's external-ref envelope embeds `externalRef0.N400`. The two struct shapes are no longer identical, so cross-package response casts (the standard pattern for sharing error shapes across services) stop compiling — the regression filed as #2010. Investigation showed there is no smarter alternative: non-strict server modes emit no top-level type for `components/responses/...`, only `models: true` (gives the bare alias) and `strict-server: true` (gives the `JSONResponse` envelope, which is also the only form that carries a `Headers` field in the with-headers case) do. Changes: - Drop the `$isExternalRef` carve-out from the three strict-interface templates so external refs use the same `JSONResponse` embedding as internal refs. - Update `internal/test/issues/issue-removed-external-ref` golden output to match. - Update `internal/test/issues/issue-2113`'s common-package config to also generate `strict-server: true`. The fixture was relying on the PR #1387 behavior; under the new policy the destination of a strict-server external ref must also generate a strict server, so `StandardErrorJSONResponse` is in scope. - Add `internal/test/issues/issue-2010` regression fixture: two specs with strict-server, the second `$ref`s the first's `components/responses/400`, and the test exercises the cross-package cast that was broken. - README: note the cross-spec strict-server requirement under the strict-server section. The earlier two commits of #1387 are kept: the `Schema.IsExternalRef` helper, and the alias-vs-defined-type fix for content-schema external refs (which is a genuinely independent bug fix — methods can't be attached to non-local aliases). BREAKING CHANGE: external `$ref` to a `components/responses/...` from a strict-server target now requires the destination spec to also generate `strict-server: true`. This restores cross-package response casting that worked in v2.0.0 and earlier. Co-authored-by: Claude Opus 4.7 (1M context) --- README.md | 3 + .../test/issues/issue-2010/config.base.yaml | 10 + .../test/issues/issue-2010/config.other.yaml | 12 + internal/test/issues/issue-2010/doc.go | 10 + .../issues/issue-2010/gen/spec_base/.gitempty | 0 .../issue-2010/gen/spec_base/issue.gen.go | 271 ++++++++++++++++++ .../issue-2010/gen/spec_other/.gitempty | 0 .../issue-2010/gen/spec_other/issue.gen.go | 263 +++++++++++++++++ internal/test/issues/issue-2010/issue_test.go | 26 ++ .../test/issues/issue-2010/spec-base.yaml | 27 ++ .../test/issues/issue-2010/spec-other.yaml | 14 + .../test/issues/issue-2113/config.common.yaml | 1 + .../test/issues/issue-2113/gen/api/api.gen.go | 4 +- .../issue-2113/gen/common/common.gen.go | 2 + .../gen/spec_base/issue.gen.go | 4 +- .../strict/strict-fiber-interface.tmpl | 2 - .../templates/strict/strict-interface.tmpl | 2 - .../strict/strict-iris-interface.tmpl | 2 - 18 files changed, 645 insertions(+), 8 deletions(-) create mode 100644 internal/test/issues/issue-2010/config.base.yaml create mode 100644 internal/test/issues/issue-2010/config.other.yaml create mode 100644 internal/test/issues/issue-2010/doc.go create mode 100644 internal/test/issues/issue-2010/gen/spec_base/.gitempty create mode 100644 internal/test/issues/issue-2010/gen/spec_base/issue.gen.go create mode 100644 internal/test/issues/issue-2010/gen/spec_other/.gitempty create mode 100644 internal/test/issues/issue-2010/gen/spec_other/issue.gen.go create mode 100644 internal/test/issues/issue-2010/issue_test.go create mode 100644 internal/test/issues/issue-2010/spec-base.yaml create mode 100644 internal/test/issues/issue-2010/spec-other.yaml diff --git a/README.md b/README.md index bc9b8757e7..916a21dbcd 100644 --- a/README.md +++ b/README.md @@ -1534,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. 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-2113/config.common.yaml b/internal/test/issues/issue-2113/config.common.yaml index f9803ed307..ce1b531f80 100644 --- a/internal/test/issues/issue-2113/config.common.yaml +++ b/internal/test/issues/issue-2113/config.common.yaml @@ -2,6 +2,7 @@ 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/gen/api/api.gen.go b/internal/test/issues/issue-2113/gen/api/api.gen.go index 9aa3018f10..b8a5c4a533 100644 --- a/internal/test/issues/issue-2113/gen/api/api.gen.go +++ b/internal/test/issues/issue-2113/gen/api/api.gen.go @@ -194,7 +194,9 @@ func (response ListThings200JSONResponse) VisitListThingsResponse(w http.Respons return err } -type ListThings400JSONResponse struct{ externalRef0.StandardError } +type ListThings400JSONResponse struct { + externalRef0.StandardErrorJSONResponse +} func (response ListThings400JSONResponse) VisitListThingsResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-2113/gen/common/common.gen.go b/internal/test/issues/issue-2113/gen/common/common.gen.go index 8d16de5f8f..6a6bc94a1c 100644 --- a/internal/test/issues/issue-2113/gen/common/common.gen.go +++ b/internal/test/issues/issue-2113/gen/common/common.gen.go @@ -11,3 +11,5 @@ type ProblemDetails struct { // StandardError defines model for StandardError. type StandardError = ProblemDetails + +type StandardErrorJSONResponse ProblemDetails 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 57ad01efb4..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 @@ -215,7 +215,9 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index baad4ab4e5..2a1905066e 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -42,8 +42,6 @@ {{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}} diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 39fbc98855..237f668b1e 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -42,8 +42,6 @@ {{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}} diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 5d9b5965c0..dbef961d3e 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -42,8 +42,6 @@ {{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}} From 08b30183ea8ab37db88e457634f2338f47222428 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Thu, 30 Apr 2026 22:37:33 -0700 Subject: [PATCH 261/293] Route server enums through general enums codegen (#2358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Route server enums through general enums codegen The server-URL codegen feature (`generate.server-urls: true`) re-implemented its own enum emission inside server-urls.tmpl rather than going through the generic GenerateEnums / GenerateTypes pipeline used by every other enum-bearing schema in the codebase. That self-contained path quietly accumulated five distinct bugs: * Two `const ...VariableDefault` declarations whenever an enum value's `ucFirst` form was the literal string `Default` (e.g. `enum: [default]`), producing uncompilable Go (#2003). * No `Valid()` method on enum-typed variables, with a literal "TODO ... will validate that the value is part of the ... enum" comment emitted in the generated function body (#2006). * Variables declared in `variables:` but absent from the URL still produced a type, constant, function parameter, and a no-op `strings.ReplaceAll` call (#2004). * `{name}` placeholders in the URL with no entry in `variables:` were left in the URL after substitution and tripped the trailing `{`/`}` runtime check on every call, making the generated function permanently unusable (#2005). * When `default` was set to a value not in `enum` (which OpenAPI 3 declares invalid), the template emitted `const FooDefault Foo = FooDevelopment` where `FooDevelopment` was never declared, surfacing the spec error as a confusing Go compile failure (#2007). All five share one root cause: server-URL variables didn't reach the type and enum codegen passes that already exist for every other schema. Changes: - Add `ForceEnumPrefix` to TypeDefinition. GenerateEnums OR's it into PrefixTypeName so synthesized server-URL enum types keep the existing always-prefixed identifier shape (`` rather than the bare `` the generic path would otherwise emit when no conflict is detected). - Add BuildServerURLTypeDefinitions in pkg/codegen/server_urls.go. It extracts enum-typed used variables from spec.Servers, synthesizes a TypeDefinition per variable, and validates `default ∈ enum` at codegen time so #2007 spec violations are caught with a clear error rather than emitted as broken Go. - Wire BuildServerURLTypeDefinitions into the `generate.server-urls` gate so the synthesized types flow through GenerateTypes (typedef.tmpl) and GenerateEnums (constants.tmpl) regardless of `generate.models`. This gives server-URL enum variables the same `type X string`, `const ( ... )` block, and `Valid()` method as any other enum-bearing schema. - Drop type/const emission for enum-typed variables from server-urls.tmpl; it now emits only the per-server function (which calls `.Valid()` on each enum-typed parameter) and any non-enum variable scaffolding. - Add ServerObjectDefinition.UsedVariables and UndeclaredPlaceholders helpers + extract serverObjectDefinitions, the name-deconfliction pass shared by both GenerateServerURLs and BuildServerURLTypeDefinitions, so the type pipeline and the function-body pipeline see the same identifiers. - Extend genServerURLWithVariablesFunctionParams to take undeclared placeholders, emitting them as plain `string` parameters alongside the declared variables (sorted together for stable output). User-visible naming change: for enum-typed server-URL variables only, the default-pointer constant is renamed from `Default` to `DefaultValue`. This is what makes the #2003 collision impossible permanently — the enum-value namespace and the default-pointer namespace are distinct regardless of what string values appear in the spec. Non-enum variables keep their existing `Default` naming. Enum-value identifiers also pick up an `N` prefix for digit-leading values (e.g. an enum value `8443` becomes `N8443`) since they now flow through SchemaNameToTypeName, matching how every other enum in the codegen names digit-leading values. The example fixture at examples/generate/serverurls/api.yaml gains two new servers: one with `enum: [default, 443]` to lock in the #2003 fix end-to-end, and one with an undeclared `{tenant}` placeholder for #2005. The existing `noDefault: {}` declared-but-unused variable now demonstrates the #2004 filtering. Three previously-identical localhost URLs are given unique ports (80/81/82) to comply with OpenAPI's URL-uniqueness requirement. Closes #2003 Closes #2004 Closes #2005 Closes #2006 Closes #2007 Supersedes #2045 Co-Authored-By: Claude Opus 4.7 (1M context) * Address PR #2358 review: minimize identifier churn Greptile's review flagged that the original PR shipped several unconditional behaviour changes to the generated API surface, none of which were intrinsic to the bug fixes: * `genServerURLWithVariablesFunctionParams` gained a third argument, breaking any user-supplied custom `server-urls.tmpl` override that called it with the previous two-argument form. * Digit-leading enum values acquired an `N` prefix (e.g. `Variable8443` became `VariableN8443`), an incidental side-effect of routing through `SchemaNameToTypeName` even though the enclosing type prefix already provided a leading letter. * The default-pointer constant was unconditionally renamed from `Default` to `DefaultValue` for every enum-typed variable, breaking adopters whose specs had no collision and whose code compiled cleanly under the old codegen. Greptile also identified a latent bug: when two enum values fold to the same identifier suffix (e.g. `enum: ["foo", "Foo"]`, both `ucFirst` to `Foo`), `SanitizeEnumNames`' numeric-suffix dedup produced `Foo` and `Foo1`, but the template's default-pointer emitted `{{ $v.Default | schemaNameToTypeName | sanitizeGoIdentity }}` without the suffix, so the pointer referenced an undeclared identifier. Changes: - Revert `genServerURLWithVariablesFunctionParams` to its original two-argument signature. A new `ServerObjectDefinition.NewServerFunctionParams` method now returns the full parameter list (typed declared variables plus plain-`string` undeclared placeholders, sorted together alphabetically), and the template calls `{{ .NewServerFunctionParams }}` instead of the helper. Any user-supplied custom template that calls `genServerURLWithVariablesFunctionParams` directly keeps working. - Replace `SanitizeEnumNames` (which forces digit-leading values through `SchemaNameToTypeName` and adds the `N` prefix) with a small in-package helper `serverURLEnumKeys` that uses `UppercaseFirstCharacter` directly, plus the same ``/`1`/`2` numeric-suffix dedup. Digit-leading values stay digit-leading; identifiers for non-colliding specs are byte-for-byte identical to what the pre-PR template produced. - Make the `Default` to `DefaultValue` rename asymmetric. A new `ServerObjectDefinition.EnumDefaultPointers` method pre-computes each enum-typed variable's default-pointer info; it switches to `DefaultValue` only when an enum value's identifier suffix is the literal string "Default" (i.e. exactly the spec pattern that produced #2003's duplicate-const compile error before this fix). Adopters whose specs compiled cleanly under the old codegen keep their `Default` constant. - The same `EnumDefaultPointers` data carries the post-dedup target identifier, so the template emits `const Default = Foo1` rather than recomputing via `schemaNameToTypeName | sanitizeGoIdentity`. The pointer always agrees with whatever name the const-block actually produced. - Drop the `schemaNameToTypeName` and `sanitizeGoIdentity` calls from `server-urls.tmpl` accordingly. The template now iterates pre-computed `.EnumDefaultPointers` and `.NewServerFunctionParams` rather than reconstructing identifier names itself. Test coverage: - `pkg/codegen/server_urls_test.go` gains four `TestEnumDefaultPointers` subtests pinning the asymmetric-rename behaviour, the post-dedup reference, and the absence of the `N` prefix. - `examples/generate/serverurls/api.yaml` adds a server with `enum: ["foo", "Foo"]` exercising the dedup case end-to-end. - `examples/generate/serverurls/gen_test.go` gains `TestServerUrlCaseOnlyEnumCollision` confirming the generated code compiles, the post-dedup constants are distinct, and the default-pointer references the right one. Net effect for adopters of the original `fix/enums` PR vs. `main`: * Helper signature unchanged. * Enum value identifiers unchanged for non-colliding specs. * Default-pointer constant name unchanged for non-colliding specs. * `noDefault`-style declared-but-unused parameters are still dropped (the #2004 fix; the parameter was a no-op). * Function calls `.Valid()` on enum-typed parameters (the #2006 fix). * Specs that previously failed to compile (#2003 collision, case-only-different enum values) now compile. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- examples/generate/serverurls/api.yaml | 53 +++- examples/generate/serverurls/gen.go | 148 ++++++++-- examples/generate/serverurls/gen_test.go | 112 ++++++-- pkg/codegen/codegen.go | 25 +- pkg/codegen/schema.go | 8 + pkg/codegen/server_urls.go | 346 +++++++++++++++++++++-- pkg/codegen/server_urls_test.go | 234 +++++++++++++++ pkg/codegen/template_helpers.go | 7 + pkg/codegen/templates/server-urls.tmpl | 85 ++++-- 9 files changed, 921 insertions(+), 97 deletions(-) create mode 100644 pkg/codegen/server_urls_test.go diff --git a/examples/generate/serverurls/api.yaml b/examples/generate/serverurls/api.yaml index ec7c73a5e2..53a5d807f8 100644 --- a/examples/generate/serverurls/api.yaml +++ b/examples/generate/serverurls/api.yaml @@ -26,22 +26,57 @@ servers: 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 type that's defined, but doesn't have a default + # 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: {} - # # TODO this conflict will cause broken generated code https://github.com/oapi-codegen/oapi-codegen/issues/2003 - # conflicting: - # enum: - # - 'default' - # - '443' - # default: 'default' +# 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:80 +- url: http://localhost:81 description: Development server # make sure that the lowercase `description` gets converted to an uppercase -- url: http://localhost:80 +- url: http://localhost:82 description: some lowercase name # there may be URLs on their own, without a `description` - url: http://localhost:443 diff --git a/examples/generate/serverurls/gen.go b/examples/generate/serverurls/gen.go index b7d3485430..5f0feea91b 100644 --- a/examples/generate/serverurls/gen.go +++ b/examples/generate/serverurls/gen.go @@ -8,9 +8,112 @@ import ( "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" @@ -18,7 +121,7 @@ const ServerUrlDevelopmentServer = "https://development.gigantic-server.com/v1" const ServerUrlDevelopmentServer1 = "http://localhost:80" // ServerUrlDevelopmentServer2 defines the Server URL for Development server -const ServerUrlDevelopmentServer2 = "http://localhost:80" +const ServerUrlDevelopmentServer2 = "http://localhost:81" // ServerUrlHttplocalhost443 defines the Server URL for http://localhost:443 const ServerUrlHttplocalhost443 = "http://localhost:443" @@ -27,7 +130,7 @@ const ServerUrlHttplocalhost443 = "http://localhost:443" const ServerUrlProductionServer = "https://api.gigantic-server.com/v1" // ServerUrlSomeLowercaseName defines the Server URL for some lowercase name -const ServerUrlSomeLowercaseName = "http://localhost:80" +const ServerUrlSomeLowercaseName = "http://localhost:82" // ServerUrlStagingServer defines the Server URL for Staging server const ServerUrlStagingServer = "https://staging.gigantic-server.com/v1" @@ -38,35 +141,24 @@ type ServerUrlTheProductionAPIServerBasePathVariable string // ServerUrlTheProductionAPIServerBasePathVariableDefault is the default value for the `basePath` variable for ServerUrlTheProductionAPIServer const ServerUrlTheProductionAPIServerBasePathVariableDefault = "v2" -// ServerUrlTheProductionAPIServerNoDefaultVariable is the `noDefault` variable for ServerUrlTheProductionAPIServer -type ServerUrlTheProductionAPIServerNoDefaultVariable string - -// ServerUrlTheProductionAPIServerPortVariable is the `port` variable for ServerUrlTheProductionAPIServer -type ServerUrlTheProductionAPIServerPortVariable string - -// ServerUrlTheProductionAPIServerPortVariable8443 is one of the accepted values for the `port` variable for ServerUrlTheProductionAPIServer -const ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443" - -// ServerUrlTheProductionAPIServerPortVariable443 is one of the accepted values for the `port` variable for ServerUrlTheProductionAPIServer -const ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443" - -// ServerUrlTheProductionAPIServerPortVariableDefault is the default choice, for the accepted values for the `port` variable for ServerUrlTheProductionAPIServer -const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443 - // 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, noDefault ServerUrlTheProductionAPIServerNoDefaultVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) { +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, "{noDefault}", string(noDefault)) - - // TODO in the future, this will validate that the value is part of the ServerUrlTheProductionAPIServerPortVariable enum u = strings.ReplaceAll(u, "{port}", string(port)) u = strings.ReplaceAll(u, "{username}", string(username)) @@ -76,3 +168,17 @@ func NewServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServer 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 index 573fb5f2e5..6968ed3fe2 100644 --- a/examples/generate/serverurls/gen_test.go +++ b/examples/generate/serverurls/gen_test.go @@ -9,41 +9,51 @@ import ( ) func TestServerUrlTheProductionAPIServer(t *testing.T) { - t.Run("when no values are provided, it does not error", func(t *testing.T) { - serverUrl, err := NewServerUrlTheProductionAPIServer("", "", "", "") - require.NoError(t, err) - - assert.Equal(t, "https://.gigantic-server.com:/", serverUrl) - - // NOTE that ideally this should fail as it doesn't /seem/ to provide a valid URL, but it does seem to be valid - _, err = url.Parse(serverUrl) - require.NoError(t, err) + 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") }) - // TODO:when we validate enums, this will need more testing https://github.com/oapi-codegen/oapi-codegen/issues/2006 - t.Run("when values that are not part of the enum are provided, it does not error", func(t *testing.T) { + t.Run("when a value not in the enum is provided, it errors", func(t *testing.T) { invalidPort := ServerUrlTheProductionAPIServerPortVariable("12345") - serverUrl, err := NewServerUrlTheProductionAPIServer( + _, err := NewServerUrlTheProductionAPIServer( ServerUrlTheProductionAPIServerBasePathVariableDefault, - ServerUrlTheProductionAPIServerNoDefaultVariable(""), invalidPort, ServerUrlTheProductionAPIServerUsernameVariableDefault, ) - require.NoError(t, err) - - assert.Equal(t, "https://demo.gigantic-server.com:12345/v2", serverUrl) + 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, - ServerUrlTheProductionAPIServerNoDefaultVariable(""), 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) }) } @@ -52,3 +62,71 @@ func TestXGoName(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/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index afb0f0e3db..22317bda16 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -271,10 +271,31 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { var serverURLsDefinitions string if opts.Generate.ServerURLs { - serverURLsDefinitions, err = GenerateServerURLs(t, spec) + // 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 @@ -993,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, }) } } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index bf46a67a63..d9941381a1 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -259,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 diff --git a/pkg/codegen/server_urls.go b/pkg/codegen/server_urls.go index 48ef564d26..b70a52fd54 100644 --- a/pkg/codegen/server_urls.go +++ b/pkg/codegen/server_urls.go @@ -2,7 +2,10 @@ package codegen import ( "fmt" + "regexp" + "sort" "strconv" + "strings" "text/template" "github.com/getkin/kin-openapi/openapi3" @@ -11,6 +14,28 @@ import ( 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 @@ -20,7 +45,63 @@ type ServerObjectDefinition struct { OAPISchema *openapi3.Server } -func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) { +// 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 { @@ -28,7 +109,7 @@ func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) if goNameExt, ok := server.Extensions[extGoName]; ok { customName, err := extParseGoFieldName(goNameExt) if err != nil { - return "", fmt.Errorf("invalid value for %q: %w", extGoName, err) + return nil, fmt.Errorf("invalid value for %q: %w", extGoName, err) } if customName != "" { name = customName @@ -49,20 +130,11 @@ func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) continue } - // otherwise, try appending a number to the name + // otherwise, try appending a number to the name. Start at 1 so + // `Foo` / `Foo1` reads better than `Foo` / `Foo0`. saved := false - // NOTE that we start at 1 on purpose, as - // - // ... ServerURLDevelopmentServer - // ... ServerURLDevelopmentServer1` - // - // reads better than: - // - // ... ServerURLDevelopmentServer - // ... ServerURLDevelopmentServer0 for i := 1; i < 1+serverURLSuffixIterations; i++ { suffixed := name + strconv.Itoa(i) - // and then store it if there's no conflict if _, suffixConflict := names[suffixed]; !suffixConflict { names[suffixed] = server saved = true @@ -74,20 +146,258 @@ func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) continue } - // otherwise, error - return "", fmt.Errorf("failed to create a unique name for the Server URL (%#v) with description (%#v) after %d iterations", server.URL, server.Description, serverURLSuffixIterations) + 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)) - i := 0 - for _, k := range keys { + for i, k := range keys { servers[i] = ServerObjectDefinition{ GoName: k, OAPISchema: names[k], } - i++ + } + 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..2105649bfb --- /dev/null +++ b/pkg/codegen/server_urls_test.go @@ -0,0 +1,234 @@ +package codegen + +import ( + "testing" + + "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)") +} + +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 1beaba0b3f..1b46105323 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -331,6 +331,13 @@ func stripNewLines(s string) string { // // 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) diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl index 3f1fdfe734..ccb1786e73 100644 --- a/pkg/codegen/templates/server-urls.tmpl +++ b/pkg/codegen/templates/server-urls.tmpl @@ -1,54 +1,79 @@ {{ range . }} -{{ if eq 0 (len .OAPISchema.Variables) }} -{{/* URLs without variables are straightforward, so we'll create them a constant */}} +{{ $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 }}{{ .OAPISchema.Description }}{{ else }}{{ .OAPISchema.URL }}{{ end }} const {{ .GoName}} = "{{ .OAPISchema.URL }}" {{ else }} {{/* URLs with variables are not straightforward, as we may need multiple types, and so will model them as a function */}} -{{/* first, we'll start by generating requisite types */}} - {{ $goName := .GoName }} -{{ range $k, $v := .OAPISchema.Variables }} + +{{/* + 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 - {{ range $v.Enum }} - {{/* TODO this may result in broken generated code if any of the `enum` values are the literal value `default` https://github.com/oapi-codegen/oapi-codegen/issues/2003 */}} - // {{ $prefix }}{{ . | ucFirst }} is one of the accepted values for the `{{ $k }}` variable for {{ $goName }} - const {{ $prefix }}{{ . | ucFirst }} {{ $prefix }} = "{{ . }}" - {{ end }} - - {{/* TODO we should introduce a `Valid() error` method to enums https://github.com/oapi-codegen/oapi-codegen/issues/2006 */}} - {{ if $v.Default }} - {{ if gt (len $v.Enum) 0 }} - {{/* if we have an enum, we should use the type defined for it for its default value - and reference the constant we've already defined for the value */}} - {{/* TODO this may result in broken generated code if any of the `enum` values are the literal value `default` https://github.com/oapi-codegen/oapi-codegen/issues/2003 */}} - {{/* TODO this may result in broken generated code if the `default` isn't found in `enum` (which is an issue with the spec) https://github.com/oapi-codegen/oapi-codegen/issues/2007 */}} - // {{ $prefix }}Default is the default choice, for the accepted values for the `{{ $k }}` variable for {{ $goName }} - const {{ $prefix }}Default {{ $prefix }} = {{ $prefix }}{{ $v.Default | ucFirst }} - {{ else }} - // {{ $prefix }}Default is the default value for the `{{ $k }}` variable for {{ $goName }} - const {{ $prefix }}Default = "{{ $v.Default }}" - {{ end }} + // {{ $prefix }}Default is the default value for the `{{ $k }}` variable for {{ $goName }} + const {{ $prefix }}Default = "{{ $v.Default }}" {{ 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 {{ .OAPISchema.Description }}, with the provided variables. -func New{{ .GoName }}({{ genServerURLWithVariablesFunctionParams .GoName .OAPISchema.Variables }}) (string, error) { +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 }}" - {{ range $k, $v := .OAPISchema.Variables }} + {{ range $k, $v := $usedVars }} {{- $placeholder := printf "{%s}" $k -}} - {{- if gt (len $v.Enum) 0 -}} - {{/* TODO https://github.com/oapi-codegen/oapi-codegen/issues/2006 */}} - // TODO in the future, this will validate that the value is part of the {{ printf "%s%sVariable" $goName ($k | ucFirst) }} enum - {{ end -}} 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) From b363ca5db8465d8772855797a8fb56918e8264b3 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Fri, 1 May 2026 10:17:31 +0400 Subject: [PATCH 262/293] refactor(codegen): better Swagger compression, modern naming (#1909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(codegen): better Swagger compression * test(compatibility): Regenerate test spec * Add GetSpec/GetSpecJSON; revert const-concat embed format Three follow-ups to PR #1909, all in `pkg/codegen/templates/inline.tmpl` (plus the regenerated `*.gen.go` files and migrated callers): 1. Revert the embedded spec back to `var swaggerSpec = []string{...}`. PR #1909 replaced the historical slice-of-chunks form with a single `const swaggerSpec = "" + "chunk" + "chunk" + ...`. With thousands of 80-char chunks (large APIs produce them) the Go compiler folds the chained `+` at compile time, and that fold is materially slower than parsing a slice literal. `decodeSpec` now joins the slice via `strings.Join` before base64-decoding; flate compression, base64 encoding, the 80-char chunk size, the lazy `decodeSpecCached` / `rawSpec` pipeline, and `PathToRawSpec` all stay exactly as PR #1909 landed them. 2. Add `GetSpec() (*openapi3.T, error)` as the canonical accessor, and demote `GetSwagger()` to a `// Deprecated:` thin wrapper. The kin-openapi spec type was renamed from `openapi3.Swagger` to `openapi3.T` years ago; `GetSwagger`'s name is a stale relic. `GetSpec` carries the body that `GetSwagger` had, and `GetSwagger` becomes a one-line `return GetSpec()` retained for backwards compatibility. External callers still upgrading to a newer version of oapi-codegen will see the `// Deprecated:` hint surfaced by gopls/godoc; in-tree callers across `examples/` and `internal/test/` are migrated to `GetSpec()` because the repo's lint rule rejects calls into deprecated functions and would otherwise block CI. 3. Add `GetSpecJSON() ([]byte, error)` returning the embedded JSON. Decompressed, base64-decoded, but not unmarshaled into `*openapi3.T`. A one-line wrapper around the existing `rawSpec()` cache, so repeated calls don't re-decompress. This fills a long-standing gap: callers who want to operate on the raw OpenAPI document (re-marshal to YAML, hand to a different parser, run an overlay, dump to disk) previously had to either invoke `openapi3.T.MarshalJSON` after `GetSpec` or hand-roll base64+flate decode. Migrated callers (mechanical; no logic changes): - 7 user-side example files under `examples/` (petstore variants for each framework, authenticated-api echo + stdhttp). - 12 test files under `examples/petstore-expanded/*/petstore_test.go`, `internal/test/externalref/imports_test.go`, `internal/test/issues/issue1825/overlay_test.go`, `internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec_test.go`. New test: - `examples/petstore-expanded/chi/petstore_test.go::TestSpecAccess` covers `GetSpec` and `GetSpecJSON` end-to-end (asserts the bytes are valid JSON and the parsed spec has a non-empty `OpenAPI` version field). `GetSwagger` is intentionally not exercised — its body is `return GetSpec()` and the lint rule blocks an in-tree call. If we later want regression coverage for the wrapper specifically, one test annotated with `//nolint:staticcheck // SA1019` would do it. Verification: - `make generate` is idempotent; spot-checking `examples/petstore-expanded/chi/api/petstore.gen.go` confirms the slice form, the three new accessors, and the `// Deprecated:` marker on `GetSwagger`. - `make test` passes (exit 0) across the root module and all eight child modules. - `make lint` reports `0 issues.` across the same nine modules — no remaining in-tree calls into the deprecated wrapper. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Marcin Romaszewicz Co-authored-by: Claude Opus 4.7 (1M context) --- .../authenticated-api/echo/api/api.gen.go | 87 +++++---- .../authenticated-api/echo/server/server.go | 2 +- .../authenticated-api/stdhttp/api/api.gen.go | 87 +++++---- .../stdhttp/server/server.go | 2 +- examples/overlay/api/ping.gen.go | 76 +++++--- .../petstore-expanded/chi/api/petstore.gen.go | 120 +++++++------ examples/petstore-expanded/chi/petstore.go | 2 +- .../petstore-expanded/chi/petstore_test.go | 23 ++- .../echo-v5/api/petstore-server.gen.go | 116 +++++++----- .../petstore-expanded/echo-v5/petstore.go | 2 +- .../echo-v5/petstore_test.go | 2 +- .../echo/api/petstore-server.gen.go | 116 +++++++----- examples/petstore-expanded/echo/petstore.go | 2 +- .../petstore-expanded/echo/petstore_test.go | 2 +- .../echo/pkg_codegen_petstore_test.go | 8 +- .../fiber/api/petstore-server.gen.go | 116 +++++++----- examples/petstore-expanded/fiber/petstore.go | 2 +- .../gin/api/petstore-server.gen.go | 116 +++++++----- examples/petstore-expanded/gin/petstore.go | 2 +- .../gorilla/api/petstore.gen.go | 120 +++++++------ .../petstore-expanded/gorilla/petstore.go | 2 +- .../gorilla/petstore_test.go | 2 +- .../iris/api/petstore-server.gen.go | 118 +++++++------ examples/petstore-expanded/iris/petstore.go | 2 +- .../stdhttp/api/petstore.gen.go | 120 +++++++------ .../petstore-expanded/stdhttp/petstore.go | 2 +- .../stdhttp/petstore_test.go | 2 +- .../strict/api/petstore-server.gen.go | 120 +++++++------ examples/petstore-expanded/strict/petstore.go | 2 +- .../petstore-expanded/strict/petstore_test.go | 2 +- .../streaming/stdhttp/sse/streaming.gen.go | 74 +++++--- internal/test/all_of/v1/openapi.gen.go | 83 +++++---- internal/test/all_of/v2/openapi.gen.go | 83 +++++---- .../spec.gen.go | 69 +++++--- .../spec_test.go | 2 +- internal/test/externalref/externalref.gen.go | 77 +++++--- internal/test/externalref/imports_test.go | 8 +- .../externalref/packageA/externalref.gen.go | 73 +++++--- .../externalref/packageB/externalref.gen.go | 70 +++++--- .../externalref/petstore/externalref.gen.go | 165 ++++++++++-------- .../test/issues/issue-1087/deps/deps.gen.go | 90 ++++++---- .../issues/issue-1093/api/child/child.gen.go | 73 +++++--- .../issue-1093/api/parent/parent.gen.go | 73 +++++--- internal/test/issues/issue-1180/issue.gen.go | 73 +++++--- .../test/issues/issue-1182/pkg1/pkg1.gen.go | 71 +++++--- .../test/issues/issue-1182/pkg2/pkg2.gen.go | 69 +++++--- .../test/issues/issue-1189/issue1189.gen.go | 69 +++++--- .../issue-1208-1209/issue-multi-json.gen.go | 69 +++++--- .../test/issues/issue-1212/pkg1/pkg1.gen.go | 69 +++++--- .../test/issues/issue-1212/pkg2/pkg2.gen.go | 68 +++++--- .../issue-1378/bionicle/bionicle.gen.go | 73 +++++--- .../issues/issue-1378/common/common.gen.go | 68 +++++--- .../issue-1378/fooservice/fooservice.gen.go | 73 +++++--- .../test/issues/issue-1397/issue1397.gen.go | 74 +++++--- .../issue-1529/strict-echo/issue1529.gen.go | 69 +++++--- .../issue-1529/strict-fiber/issue1529.gen.go | 69 +++++--- .../issue-1529/strict-iris/issue1529.gen.go | 69 +++++--- internal/test/issues/issue-312/issue.gen.go | 83 +++++---- internal/test/issues/issue-52/issue.gen.go | 73 +++++--- internal/test/issues/issue-832/issue.gen.go | 73 +++++--- .../issue-grab_import_names/issue.gen.go | 72 +++++--- .../issue-illegal_enum_names/issue.gen.go | 70 +++++--- .../issue-illegal_enum_names/issue_test.go | 22 ++- .../test/issues/issue1825/issue1825.gen.go | 69 +++++--- .../test/issues/issue1825/overlay_test.go | 2 +- .../issue1825/packageA/externalref.gen.go | 65 ++++--- .../name_normalizer.gen.go | 82 +++++---- .../name_normalizer.gen.go | 82 +++++---- .../name_normalizer.gen.go | 82 +++++---- .../to-camel-case/name_normalizer.gen.go | 82 +++++---- .../unset/name_normalizer.gen.go | 82 +++++---- .../test/parameters/chi/gen/server.gen.go | 109 +++++++----- .../test/parameters/echo/gen/server.gen.go | 109 +++++++----- internal/test/parameters/echov5/server.gen.go | 109 +++++++----- .../test/parameters/fiber/gen/server.gen.go | 105 ++++++----- .../test/parameters/gin/gen/server.gen.go | 105 ++++++----- .../test/parameters/gorilla/gen/server.gen.go | 105 ++++++----- .../test/parameters/iris/gen/server.gen.go | 105 ++++++----- .../test/parameters/stdhttp/gen/server.gen.go | 105 ++++++----- internal/test/schemas/schemas.gen.go | 117 ++++++++----- internal/test/strict-server/chi/server.gen.go | 107 +++++++----- .../test/strict-server/echo/server.gen.go | 107 +++++++----- .../test/strict-server/fiber/server.gen.go | 107 +++++++----- internal/test/strict-server/gin/server.gen.go | 107 +++++++----- .../test/strict-server/gorilla/server.gen.go | 107 +++++++----- .../test/strict-server/iris/server.gen.go | 107 +++++++----- .../test/strict-server/stdhttp/server.gen.go | 107 +++++++----- pkg/codegen/inline.go | 21 +-- pkg/codegen/templates/imports.tmpl | 2 +- pkg/codegen/templates/inline.tmpl | 63 ++++--- 90 files changed, 3715 insertions(+), 2326 deletions(-) diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index 9cada0501d..d9b8dffea2 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" @@ -514,37 +514,39 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -552,7 +554,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) { @@ -570,12 +572,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() @@ -601,3 +603,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/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/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index 5a83732c25..97f16b2ff2 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" @@ -611,37 +611,39 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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 @@ -649,7 +651,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) { @@ -667,12 +669,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() @@ -698,3 +700,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/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/overlay/api/ping.gen.go b/examples/overlay/api/ping.gen.go index 757cd1c6b4..0d6794fc38 100644 --- a/examples/overlay/api/ping.gen.go +++ b/examples/overlay/api/ping.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "fmt" "net/http" @@ -170,34 +170,35 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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/1xSwW7UMBD9FWvgAFJ2ve2Ki28VQmjFYVeCW9WD60xil8Rj7ElpVfnf0Ti7FHqaePLs", - "997MewFHc6KIkQuYFyjO42zb54niKDVlSpg5YOumsHbxyc5pQjCQBNcBPyc5Fc6CqLWDjL+WkLEHc7te", - "u/uLovsHdAwdPG1G2kQ7S/P4iDmHvsfYqKu8EeJAQseBG9mXlVYxqRD74Cyj8vRbzktBxR7VMWG8OR2U", - "PDfZZ1USujAINFBUHzxzKkbrMbBf7reOZn28OegzevP9X/RH6OARcwkUwcDVdrfdNc10BtuUpiAGxfbi", - "eMnYX35C7YASRpsCGNif7ybLvs1R234OUduFqTg7rVOtHejLgEdkKT0Wl0PiVcJnj+6nYm+5WRWboai8", - "xBjiqI7foHHmJv4gur4in0LbT8aSKJZ1i9e7nRRHkTE2nmZlda0fipBdwiBf7zMOYOCdfk2LPkdFvy7r", - "f60nzAPlWVkllpSkAQu3ZBTMMlYwt28N/vCoehzsMrFaUVvoYMkTGJDNGa0ncnbyVNjsP11d76He1Vrr", - "nwAAAP//QsRK0MkCAAA=", + "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=", } -// 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 @@ -205,7 +206,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) { @@ -223,12 +224,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() @@ -254,3 +255,22 @@ func GetSwagger() (swagger *openapi3.T, err error) { } return } + +// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI +// specification: decompressed but not unmarshaled. External references +// are not resolved here; the bytes are the spec exactly as embedded by +// codegen. The result is cached at package init time, so repeated calls +// are cheap. +func GetSpecJSON() ([]byte, error) { + return rawSpec() +} + +// GetSwagger returns the OpenAPI specification corresponding to the +// generated code in this file. +// +// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger +// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for +// backwards compatibility. +func GetSwagger() (*openapi3.T, error) { + return GetSpec() +} diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go index f599568124..338c39e73f 100644 --- a/examples/petstore-expanded/chi/api/petstore.gen.go +++ b/examples/petstore-expanded/chi/api/petstore.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "errors" "fmt" @@ -355,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 @@ -410,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) { @@ -428,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() @@ -459,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/petstore-server.gen.go b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go index 7dc2404777..557c96abf5 100644 --- a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go +++ b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "fmt" "net/http" @@ -160,54 +160,55 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -215,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) { @@ -233,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() @@ -264,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-v5/petstore.go b/examples/petstore-expanded/echo-v5/petstore.go index 9742cc1939..7b15a9fdd5 100644 --- a/examples/petstore-expanded/echo-v5/petstore.go +++ b/examples/petstore-expanded/echo-v5/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/echo-v5/petstore_test.go b/examples/petstore-expanded/echo-v5/petstore_test.go index 61d0530a23..3809bb5544 100644 --- a/examples/petstore-expanded/echo-v5/petstore_test.go +++ b/examples/petstore-expanded/echo-v5/petstore_test.go @@ -37,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, diff --git a/examples/petstore-expanded/echo/api/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go index 8565fafd5e..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" @@ -160,54 +160,55 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -215,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) { @@ -233,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() @@ -264,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 7287d2b354..a764f00b04 100644 --- a/examples/petstore-expanded/echo/petstore.go +++ b/examples/petstore-expanded/echo/petstore.go @@ -20,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) diff --git a/examples/petstore-expanded/echo/petstore_test.go b/examples/petstore-expanded/echo/petstore_test.go index 092e6238e8..eb3b8c1652 100644 --- a/examples/petstore-expanded/echo/petstore_test.go +++ b/examples/petstore-expanded/echo/petstore_test.go @@ -37,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, 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 c8f2b20b48..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" @@ -195,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{ - - "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 @@ -250,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) { @@ -268,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() @@ -299,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/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go index 52ce7a8087..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" @@ -174,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 @@ -229,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) { @@ -247,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() @@ -278,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 dea4e55e54..3ed8b4c27e 100644 --- a/examples/petstore-expanded/gorilla/api/petstore.gen.go +++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "errors" "fmt" @@ -322,54 +322,55 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -377,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) { @@ -395,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() @@ -426,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 9f52757c5c..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" @@ -144,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 @@ -199,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) { @@ -217,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() @@ -248,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/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go index aa60a0891e..9ae158e3fd 100644 --- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go +++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go @@ -7,7 +7,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "errors" "fmt" @@ -327,54 +327,55 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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 @@ -382,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) { @@ -400,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() @@ -431,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/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 4877d1d564..e35edad725 100644 --- a/examples/petstore-expanded/strict/api/petstore-server.gen.go +++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -619,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 @@ -674,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) { @@ -692,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() @@ -723,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/stdhttp/sse/streaming.gen.go b/examples/streaming/stdhttp/sse/streaming.gen.go index 94aa81e3e4..cd2a15e01c 100644 --- a/examples/streaming/stdhttp/sse/streaming.gen.go +++ b/examples/streaming/stdhttp/sse/streaming.gen.go @@ -7,7 +7,7 @@ package sse import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "fmt" @@ -285,33 +285,34 @@ func (sh *strictHandler) GetStream(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/2SSQW/bMAyF/wrB0wY4qZzc9AeGDcU2wD3tptpMwsKiNIkJVhT+7wPlLV2yi2VQeO97", - "fNAbshwS+jdU1pnQ48AxzwRfhm9fH2HQQiGyHGGgcuGRsMMLlcpJ0GO/dVuHS4cpk4TM6HHfRh3moKdq", - "tg/2OZLaMVEdC2dd1d9LuvBEFQLUhoF0aFiY0niOJFrhQxKCTAVmFuog5DzzGMzg4aUmmT/CmEQDi0UM", - "oBypaogZgkxQ6eeZZCSQc3ymssUWtDT55wk9fiJdF8QOC9WcpFILvXPODvMmadH/I9uQfgXryn7/stD3", - "HVoM9Lhzu/2m7zc799Q7v3feuR/WVh1PFIOpcrFAyiv13eO+quF2EytKTwR0IVFbS1+zAVmUjlSMsUa4", - "93m69nPvcEglBkWPU1DaNPXVtmphOeKyXCfp+YVGxcVGt4R/n01T1HOMobz+uYJHFqrv98vyOwAA///z", - "FQ4NgQIAAA==", + "ZJJBb9swDIX/CsHTBjipnNz0B4YNxTbAPe2m2kzCwqI0iQlWFP7vA+UtXbKLZVB473t80BuyHBL6N1TW", + "mdDjwDHPBF+Gb18fYdBCIbIcYaBy4ZGwwwuVyknQY791W4dLhymThMzocd9GHeagp2q2D/Y5ktoxUR0L", + "Z13V30u68EQVAtSGgXRoWJjSeI4kWuFDEoJMBWYW6iDkPPMYzODhpSaZP8KYRAOLRQygHKlqiBmCTFDp", + "55lkJJBzfKayxRa0NPnnCT1+Il0XxA4L1ZykUgu9c84O8yZp0f8j25B+BevKfv+y0PcdWgz0uHO7/abv", + "Nzv31Du/d965H9ZWHU8Ug6lysUDKK/Xd476q4XYTK0pPBHQhUVtLX7MBWZSOVIyxRrj3ebr2c+9wSCUG", + "RY9TUNo09dW2amE54rJcJ+n5hUbFxUa3hH+fTVPUc4yhvP65gkcWqu/3y/I7AAD//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 @@ -319,7 +320,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) { @@ -337,12 +338,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 +369,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/v1/openapi.gen.go b/internal/test/all_of/v1/openapi.gen.go index db5fd302cd..46571fcce3 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" @@ -38,37 +38,39 @@ type PersonWithID struct { ID int64 `json:"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/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=", + "lJRPb9s4EMW/yoC7R0FOsIs96Bas20BAkRpo0hziABlLI4spNWTJUQzB8HcvSMn/4BZpfRrA5OO8N7/R", + "VlW2c5aJJahiq0LVUoepXJAPlmOFxnxuVPG0VX97alSh/podb82mK7Px/MJbR140BbXLtsrT9157qlXx", + "pD5qH+QOO1KZ+oRT+bx7zlRNofLaiY7vqftWB9ABEFySzGCjpYUOuUaxfoAmCgFyDQaDAGNHGax6AZsk", + "0EA5XzL33Yp8DkluY3tTw4rAk/SeqYbVAAgvtyQvEGQwBDeLModHgo78mkBamp5fsjt4GjtBttKShy/J", + "OWxaXbVg2QzgvH3TNQXY+4ZGk6lDvmSVKRkcqULZ1StVonaZuois2F5kQYEAPU1CIC0KBEeVboZDQtEk", + "DekYGnOIIYsZLfngvQ+Tb4aXD7U+dQ7EtbOaJYNNS56AsGrjEPZaowN31upxoMV2by6I17yO5m7tG3nu", + "iKWc36VZxGON9R2KKpRm+e/fYyiahdbk48UDG5equ1+G+KilLed/Smti9NzUKPJum7vsjO1y/jskg6fK", + "+howHDlsvO0A4X9PKHQYQw6lQGVZUHNYcpxqJHKCwDaAsDhdDmTAutYT/p6C7X1F8PBQzn/KXuxfc2NT", + "xlpM/O+eggS4ifFBSiwkPZWpN/JhdHSdX+VXMXXriNFpVah/8qv8OrKB0qYEZ85gRa019TjyNckl2F/R", + "6LTOATbIAihgKG6zZYIolUGwIDHADr9RBJ86aNG5YTQUZ4ZRrKxVoRYnT8bJBGc57Beqwd6kFmKgxKlE", + "54yuksDsdfrOjWzE6n1yJt5SkOfOTt3v0u9HAAAA//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 +78,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 +96,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 +127,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..b25d5bb90a 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" @@ -38,37 +38,39 @@ type PersonWithID struct { LastName string `json:"LastName"` } -// 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/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=", + "lJRPb9s4EMW/yoC7R0FOsIs96Bas20BAkRpo0hziABlLI4spNWTJUQzB8HcvSMn/4BZpfRrA5OO8N7/R", + "VlW2c5aJJahiq0LVUoepXJAPlmOFxnxuVPG0VX97alSh/podb82mK7Px/MJbR140BbXLtsrT9157qlXx", + "pD5qH+QOO1KZ+oRT+bx7zlRNofLaiY7vqftWB9ABEFySzGCjpYUOuUaxfoAmCgFyDQaDAGNHGax6AZsk", + "0EA5XzL33Yp8DkluY3tTw4rAk/SeqYbVAAgvtyQvEGQwBDeLModHgo78mkBamp5fsjt4GjtBttKShy/J", + "OWxaXbVg2QzgvH3TNQXY+4ZGk6lDvmSVKRkcqULZ1StVonaZuois2F5kQYEAPU1CIC0KBEeVboZDQtEk", + "DekYGnOIIYsZLfngvQ+Tb4aXD7U+dQ7EtbOaJYNNS56AsGrjEPZaowN31upxoMV2by6I17yO5m7tG3nu", + "iKWc36VZxGON9R2KKpRm+e/fYyiahdbk48UDG5equ1+G+KilLed/Smti9NzUKPJum7vsjO1y/jskg6fK", + "+howHDlsvO0A4X9PKHQYQw6lQGVZUHNYcpxqJHKCwDaAsDhdDmTAutYT/p6C7X1F8PBQzn/KXuxfc2NT", + "xlpM/O+eggS4ifFBSiwkPZWpN/JhdHSdX+VXMXXriNFpVah/8qv8OrKB0qYEZ85gRa019TjyNckl2F/R", + "6LTOATbIAihgKG6zZYIolUGwIDHADr9RBJ86aNG5YTQUZ4ZRrKxVoRYnT8bJBGc57Beqwd6kFmKgxKlE", + "54yuksDsdfrOjWzE6n1yJt5SkOfOTt3v0u9HAAAA//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 +78,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 +96,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 +127,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/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 index 030c8277d9..f11ee94195 100644 --- 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 @@ -5,7 +5,7 @@ package preserveoriginaloperationidcasinginembeddedspec import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "fmt" "net/url" @@ -15,30 +15,32 @@ import ( "github.com/getkin/kin-openapi/openapi3" ) -// 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/7SOwUrFQAxFf0Xuevpe1d3sHuJCBBH8AJnXxjbaZkIThFLm32XGlR9gNjcEcu45wPKR", - "EQ84+0KIWPcbUxoQ8E2bcRZE3J76U48SkJUkKSPivp0CNPls9f+s5DVHWsipbllpS85ZnkZE+MzWsXWp", - "+6Jrul5kfEgrLe9vL5fnRwRsZJrFqMHu+r7GkMVJGjapLjw03PnTqtUBG2ZaU5PftbqbbywTSpuA6dfo", - "r8dE/kr+H4WllJ8AAAD//+CJBDdPAQAA", + "tI7BSsVADEV/Re56+l7V3ewe4kIEEfwAmdfGNtpmQhOEUubfZcaVH2A2NwRy7jnA8pERDzj7QohY9xtT", + "GhDwTZtxFkTcnvpTjxKQlSQpI+K+nQI0+Wz1/6zkNUdayKluWWlLzlmeRkT4zNaxdan7omu6XmR8SCst", + "728vl+dHBGxkmsWowe76vsaQxUkaNqkuPDTc+dOq1QEbZlpTk9+1uptvLBNKm4Dp1+ivx0T+Sv4fhaWU", + "nwAAAP//", } -// 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 @@ -46,7 +48,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) { @@ -64,12 +66,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() @@ -95,3 +97,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/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 index 2f395b5776..01b7f91c59 100644 --- 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 @@ -9,7 +9,7 @@ import ( ) func TestSpecReturnsOperationIdAsOriginallySpecified(t *testing.T) { - spec, err := GetSwagger() + spec, err := GetSpec() require.NoError(t, err) path := spec.Paths.Find("/pet") diff --git a/internal/test/externalref/externalref.gen.go b/internal/test/externalref/externalref.gen.go index 158a922d02..82f42dfbbd 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" @@ -26,34 +26,36 @@ type Container struct { 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", + "pFRNb9swDP0rAbej0GTosINvbXdfDtupKAxGZhxttqRJTNag0H8fKDWNE6dIsl0Mmh8P7z3SfgHteu8s", + "WY5QvUDUK+oxhw/OMhpLQV58cJ4CG8olt/hJmmuU+GOgJVTwYboHmr6iTD3qX9jSXR096fpbnrqDpHYA", + "iwsB7ocA9wMAfQ7grS8p8MTn2tGbenNbO09WwjkxpJQUHOUfkKl1YTt2xjTypGfsfUdQfVKwdKFHhgqM", + "5S+fQQFvPZVXaikIMYs9HYzBV9fGfWvkYGwLQuQ1U2SBgue+k8mCAHrH6wTneVF/SFcPhFzhy5v+pEaK", + "Z/8ouXFta2gsWoFfOXY/QlcMZupzcNh27MRuZmgahoDbfeefgN5TAxWHNUlbZOR1xm4o6mA8G2cFi3hS", + "ahNjJ7yiSWQXhCrZdQ/VI+AGTYeLTnKebFMYRdc18HRCEGN7qOUK679jgbhEUlIQ6PfaBEk9FmuGdj6d", + "uyef7390SsLhncu/YvXXHjdj6Rp++tg0RraE3XxARtQfo8kdnfwbjYS8w++/f1ppT+GodCmFlDGMXbpc", + "NJw/HFCwoRDLrWaeZU1Qwe3N7GYmK0deCXBKfwMAAP//", } -// 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 +63,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) { @@ -97,12 +99,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() @@ -128,3 +130,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 a859c18af1..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" @@ -36,32 +36,34 @@ type StatusPostPayload struct { Status externalRef0.StatusEnum `json:"status"` } -// 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/5xTzW7CMAx+F2/HSIhrbkPiDNo0LghVJnEhW5pkSToNVXn3KaEIKjqp7GbX9tfvp+1A", - "2MZZQyYG4B0EcaQGS7k0XokjyfdAPveo9aoGvu3g2VMNHJ5m19tZfzhzKD7xQIsqOBJVuU2sA+etIx8V", - "FWj6iR6rWpGWuY0nR8AhRK/MAVJilyd2/0EiQtolBqtSv+T9IZjBhkZQWH9d7fNwOuXzexaQMo+3iLEN", - "axviGk/aovyvEWegzXzEDE8YrJnswzjbqa6kO4RXq8simbYBvgWUjTLAoM3R7di9rWPCluX4BkRE9U3A", - "QJm+nIq0mQ8tHqoKZeexQG8YZvWevlrlSWaaPdxugtGXv2DIR8nRL89b3c8jNQ/SLXlco0fv8ZT7nMdf", - "oQ5VKQk36/fi8r4ytQVuWq0ZWEcGnQIOkFXHYzhP0m8AAAD//1KVtScdBAAA", + "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 @@ -69,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) { @@ -93,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() @@ -124,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/packageB/externalref.gen.go b/internal/test/externalref/packageB/externalref.gen.go index 8b07f571c9..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" @@ -74,31 +74,32 @@ type User struct { Username string `json:"username"` } -// 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/4RRTUvDQBT8L6PHheB1j4LngqKX0sOavNiV/XL3rVDK/nd5a7CxtXjKhJnJm5kcMUaf", - "YqDABfqIMu7Jmw43r+808r3AlGOizJY6EYwnefIhETQKZxve0FpTeIyuUxSqh97CTN4GKNRCGTt1blF4", - "YsO1PHT5yjay/SQo2LDA696XO3Ea5zYz9PY8a+kaQbeZZmjcDKfCw9J2WKWQFpk+qs00SZTlA6f7sc+C", - "tmsKz1LrYh87/bGOQo5u4Zn8v5H6ku3nqsnZHORdlrz2A34ntxNW8ssCordhjtChOqcQEwWTLDSgkAzv", - "yzfTvgIAAP//mT+m2CQCAAA=", + "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 @@ -106,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) { @@ -124,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() @@ -155,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/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index e4b540a404..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" @@ -252,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 @@ -331,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) { @@ -355,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() @@ -386,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/issues/issue-1087/deps/deps.gen.go b/internal/test/issues/issue-1087/deps/deps.gen.go index 8066ab2b57..55a8d8e2f1 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" @@ -45,41 +45,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 +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) { @@ -105,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() @@ -136,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-1093/api/child/child.gen.go b/internal/test/issues/issue-1093/api/child/child.gen.go index d50664c315..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" @@ -188,32 +188,34 @@ func (sh *strictHandler) GetPets(ctx *gin.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/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 @@ -221,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) { @@ -245,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() @@ -276,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 6f6f7d869b..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" @@ -193,32 +193,34 @@ func (sh *strictHandler) GetPets(ctx *gin.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/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 @@ -226,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) { @@ -244,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() @@ -275,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-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index ffab4accf7..4f11b798d5 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" @@ -323,32 +323,34 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -356,7 +358,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) { @@ -374,12 +376,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() @@ -405,3 +407,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 13cce371bf..e548f06834 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" @@ -365,31 +365,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 @@ -397,7 +399,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) { @@ -421,12 +423,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() @@ -452,3 +454,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 906298efc5..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" @@ -211,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 @@ -242,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) { @@ -260,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() @@ -291,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 c13992c9b5..45bd54e759 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" @@ -531,30 +531,32 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -562,7 +564,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) { @@ -580,12 +582,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() @@ -611,3 +613,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 72270f9356..cb42ffded3 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" @@ -505,30 +505,32 @@ func (sh *strictHandler) Test(ctx *gin.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/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 @@ -536,7 +538,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) { @@ -554,12 +556,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() @@ -585,3 +587,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 2b4d87954a..34e300a96c 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" @@ -405,30 +405,32 @@ func (sh *strictHandler) Test(ctx *gin.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/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 @@ -436,7 +438,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) { @@ -460,12 +462,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() @@ -491,3 +493,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 1aeee27bac..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" @@ -242,30 +242,31 @@ type strictHandler struct { 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 @@ -273,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) { @@ -291,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() @@ -322,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-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index c9c57df5fb..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" @@ -328,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 @@ -361,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) { @@ -385,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() @@ -416,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 0e725531e7..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,7 @@ package common import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "fmt" @@ -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 b11772fd3c..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" @@ -288,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 @@ -321,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) { @@ -351,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() @@ -382,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-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index 8d51c9d305..c4330e0475 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" @@ -394,33 +394,34 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -428,7 +429,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) { @@ -446,12 +447,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() @@ -477,3 +478,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/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index 7e5a0c7929..e85c0b1bf2 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -5,7 +5,7 @@ package issue1529 import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -430,30 +430,32 @@ func (sh *strictHandler) Test(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/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", - "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", - "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", - "n0X+YG7zHQAA//9fnz6pkQEAAA==", + "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x", + "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa", + "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/", + "/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 @@ -461,7 +463,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) { @@ -479,12 +481,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() @@ -510,3 +512,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-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index 4ead2d3d10..5a9b77e70a 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -5,7 +5,7 @@ package issue1529 import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -406,30 +406,32 @@ func (sh *strictHandler) Test(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/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", - "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", - "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", - "n0X+YG7zHQAA//9fnz6pkQEAAA==", + "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x", + "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa", + "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/", + "/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 @@ -437,7 +439,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) { @@ -455,12 +457,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() @@ -486,3 +488,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-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go index 0a990102f2..e630e0fe63 100644 --- a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -5,7 +5,7 @@ package issue1529 import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -391,30 +391,32 @@ func (sh *strictHandler) Test(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/6zPMUsEMRAF4L8iT8twWbWL2FgI9pbXxDjr5cjNDMlYyLL/XRIXFizFad4072NmQZKL", - "ChNbQ1jQ0okucayv1KynfSkhQN7OlAzrujpkngWBP0txECWOmhFwf5gOt3DQaKcheNuIDxohSjVaFn55", - "R/jxHSo1FW40GnfT1CMJG/HoRNWS02j5cxPej+zbTaUZAdd+/8JvL/jh92t/Ew9XWmXOhR6PeIr1iH82", - "n0X+YG7zHQAA//9fnz6pkQEAAA==", + "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x", + "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa", + "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/", + "/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 @@ -422,7 +424,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) { @@ -440,12 +442,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() @@ -471,3 +473,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-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index e149b26d44..71fa081088 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" @@ -527,35 +527,37 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -563,7 +565,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) { @@ -581,12 +583,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() @@ -612,3 +614,22 @@ func GetSwagger() (swagger *openapi3.T, err error) { } return } + +// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI +// specification: decompressed but not unmarshaled. External references +// are not resolved here; the bytes are the spec exactly as embedded by +// codegen. The result is cached at package init time, so repeated calls +// are cheap. +func GetSpecJSON() ([]byte, error) { + return rawSpec() +} + +// GetSwagger returns the OpenAPI specification corresponding to the +// generated code in this file. +// +// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger +// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for +// backwards compatibility. +func GetSwagger() (*openapi3.T, error) { + return GetSpec() +} diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go index 07fd1b0a14..9fb77c6726 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" @@ -334,32 +334,34 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -367,7 +369,7 @@ func decodeSpec() ([]byte, error) { var rawSpec = decodeSpecCached() -// a naive cached of a decoded swagger spec +// a naive cache of the decoded OpenAPI spec func decodeSpecCached() func() ([]byte, error) { data, err := decodeSpec() return func() ([]byte, error) { @@ -385,12 +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() @@ -416,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-832/issue.gen.go b/internal/test/issues/issue-832/issue.gen.go index 4a5aa56a3d..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" @@ -53,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 @@ -86,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) { @@ -104,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() @@ -135,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-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go index 32cf049063..480b01aca8 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" @@ -391,32 +391,33 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -424,7 +425,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) { @@ -442,12 +443,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() @@ -473,3 +474,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.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go index 11a39afe9e..e5f45d16b1 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" @@ -365,31 +365,32 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -397,7 +398,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 +416,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 +447,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 77d4eb416c..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 } } } diff --git a/internal/test/issues/issue1825/issue1825.gen.go b/internal/test/issues/issue1825/issue1825.gen.go index 679963f84c..c8c5a18a5b 100644 --- a/internal/test/issues/issue1825/issue1825.gen.go +++ b/internal/test/issues/issue1825/issue1825.gen.go @@ -5,7 +5,7 @@ package issue1825 import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "fmt" "net/url" @@ -22,30 +22,32 @@ type Container struct { ObjectB *map[string]interface{} `json:"object_b,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/4SP0U7DMAxF/8Xw2K2TeOvbxAfAH1Re6m2G1rESd2Ka8u/IWQcIkPaUWNf33OsLhDhp", - "FBLL0F0ghyNNWL/PUQxZKPmgKSolY6pS3L1RsB79/5hoDx08tN+gdqG0iuEdD7Tts1LoX6prC6W5AXb3", - "AF97pfxy4TCwcRQcX39UszRTA3ZWgm5Z97j/e/w5S3Aifxd/tsRy8GgPZ9nHKrKNrkIDJ0qZo1yHj1U8", - "URrxvELVkWm4EuZgc6LhJtbjlQSVoYOn9Wa9Ae9nR29QymcAAAD//5P9oGCQAQAA", + "hI/RTsMwDEX/xfDYrZN469vEB8AfVF7qbYbWsRJ3Ypry78hZBwiQ9pRY1/fc6wuEOGkUEsvQXSCHI01Y", + "v89RDFko+aApKiVjqlLcvVGwHv3/mGgPHTy036B2obSK4R0PtO2zUuhfqmsLpbkBdvcAX3ul/HLhMLBx", + "FBxff1SzNFMDdlaCbln3uP97/DlLcCJ/F3+2xHLwaA9n2ccqso2uQgMnSpmjXIePVTxRGvG8QtWRabgS", + "5mBzouEm1uOVBJWhg6f1Zr0B72dHb1DKZwAAAP//", } -// 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 @@ -53,7 +55,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) { @@ -77,12 +79,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() @@ -108,3 +110,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/issue1825/overlay_test.go b/internal/test/issues/issue1825/overlay_test.go index 115a878fad..75cd428323 100644 --- a/internal/test/issues/issue1825/overlay_test.go +++ b/internal/test/issues/issue1825/overlay_test.go @@ -7,7 +7,7 @@ import ( ) func TestOverlayApply(t *testing.T) { - spec, err := GetSwagger() + 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/externalref.gen.go b/internal/test/issues/issue1825/packageA/externalref.gen.go index b2d5ca870b..d222870d82 100644 --- a/internal/test/issues/issue1825/packageA/externalref.gen.go +++ b/internal/test/issues/issue1825/packageA/externalref.gen.go @@ -5,7 +5,7 @@ package packagea import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "fmt" "net/url" @@ -20,28 +20,30 @@ type ObjectA struct { Name *string `json:"name,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/yTJwQ0CMQxE0V7mnApyowJqCNHAGm1sKzYHtNreUZa5zJfegW7DTakZqAeibxztyvvj", - "zZ63lT7NOVN4gbbB9fl1oiJyir5wrhWIPg1VP/teYE5tLqhAgbfc4i/nLwAA//+kHCeTdgAAAA==", + "JMnBDQIxDETRXuacCnKjAmoI0cAabWwrNge02t5RlrnMl96BbsNNqRmoB6JvHO3K++PNnreVPs05U3iB", + "tsH1+XWiInKKvnCuFYg+DVU/+15gTm0uqECBt9ziL+cvAAD//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 @@ -49,7 +51,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 +69,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 +100,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-additional-initialisms/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go index e27de44070..5e5d1f4d81 100644 --- 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 @@ -5,7 +5,7 @@ package tocamelcasewithadditionalinitialisms import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -512,35 +512,36 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -548,7 +549,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) { @@ -566,12 +567,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() @@ -597,3 +598,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-digits/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer.gen.go index 0b361107a4..ee65dae6ac 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" @@ -512,35 +512,36 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -548,7 +549,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) { @@ -566,12 +567,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() @@ -597,3 +598,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 f69341bea8..6d924715f5 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" @@ -512,35 +512,36 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -548,7 +549,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) { @@ -566,12 +567,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() @@ -597,3 +598,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 b79d538332..e9913ca86c 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" @@ -512,35 +512,36 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -548,7 +549,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) { @@ -566,12 +567,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() @@ -597,3 +598,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 4e8b5399cd..b511d10eb3 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" @@ -512,35 +512,36 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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 @@ -548,7 +549,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) { @@ -566,12 +567,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() @@ -597,3 +598,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/parameters/chi/gen/server.gen.go b/internal/test/parameters/chi/gen/server.gen.go index e191f7959c..a32748c70d 100644 --- a/internal/test/parameters/chi/gen/server.gen.go +++ b/internal/test/parameters/chi/gen/server.gen.go @@ -5,7 +5,7 @@ package chiparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "errors" @@ -1563,48 +1563,50 @@ 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", -} - -// GetSwagger returns the content of the embedded swagger specification file -// or error if failed to decode + "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) { - 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 @@ -1612,7 +1614,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) { @@ -1630,12 +1632,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() @@ -1661,3 +1663,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/parameters/echo/gen/server.gen.go b/internal/test/parameters/echo/gen/server.gen.go index ee44e88832..f55c138151 100644 --- a/internal/test/parameters/echo/gen/server.gen.go +++ b/internal/test/parameters/echo/gen/server.gen.go @@ -5,7 +5,7 @@ package echoparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "fmt" @@ -896,48 +896,50 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", -} - -// GetSwagger returns the content of the embedded swagger specification file -// or error if failed to decode + "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) { - 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 @@ -945,7 +947,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) { @@ -963,12 +965,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() @@ -994,3 +996,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/parameters/echov5/server.gen.go b/internal/test/parameters/echov5/server.gen.go index 46a5ed2ad7..fa9568f23f 100644 --- a/internal/test/parameters/echov5/server.gen.go +++ b/internal/test/parameters/echov5/server.gen.go @@ -5,7 +5,7 @@ package echov5params import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "fmt" @@ -896,48 +896,50 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", -} - -// GetSwagger returns the content of the embedded swagger specification file -// or error if failed to decode + "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) { - 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 @@ -945,7 +947,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) { @@ -963,12 +965,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() @@ -994,3 +996,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/parameters/fiber/gen/server.gen.go b/internal/test/parameters/fiber/gen/server.gen.go index a615749192..0557bc8fab 100644 --- a/internal/test/parameters/fiber/gen/server.gen.go +++ b/internal/test/parameters/fiber/gen/server.gen.go @@ -5,7 +5,7 @@ package fiberparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "fmt" @@ -1330,48 +1330,50 @@ 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{ - - "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", + "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==", } -// 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 @@ -1379,7 +1381,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) { @@ -1397,12 +1399,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() @@ -1428,3 +1430,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/parameters/gin/gen/server.gen.go b/internal/test/parameters/gin/gen/server.gen.go index 257d7106e0..5bf8e4232f 100644 --- a/internal/test/parameters/gin/gen/server.gen.go +++ b/internal/test/parameters/gin/gen/server.gen.go @@ -5,7 +5,7 @@ package ginparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "fmt" @@ -1193,48 +1193,50 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options router.GET(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber) } -// 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", + "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==", } -// 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 @@ -1242,7 +1244,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) { @@ -1260,12 +1262,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() @@ -1291,3 +1293,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/parameters/gorilla/gen/server.gen.go b/internal/test/parameters/gorilla/gen/server.gen.go index b528089ecb..489209ea0a 100644 --- a/internal/test/parameters/gorilla/gen/server.gen.go +++ b/internal/test/parameters/gorilla/gen/server.gen.go @@ -5,7 +5,7 @@ package gorillaparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "errors" @@ -1396,48 +1396,50 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", + "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==", } -// 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 @@ -1445,7 +1447,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) { @@ -1463,12 +1465,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() @@ -1494,3 +1496,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/parameters/iris/gen/server.gen.go b/internal/test/parameters/iris/gen/server.gen.go index eff396ab5a..2da66aeedf 100644 --- a/internal/test/parameters/iris/gen/server.gen.go +++ b/internal/test/parameters/iris/gen/server.gen.go @@ -5,7 +5,7 @@ package irisparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "fmt" @@ -1032,48 +1032,50 @@ 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{ - - "H4sIAAAAAAAC/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", + "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==", } -// 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 @@ -1081,7 +1083,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) { @@ -1099,12 +1101,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() @@ -1130,3 +1132,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/parameters/stdhttp/gen/server.gen.go b/internal/test/parameters/stdhttp/gen/server.gen.go index 06afd09a22..eda0976432 100644 --- a/internal/test/parameters/stdhttp/gen/server.gen.go +++ b/internal/test/parameters/stdhttp/gen/server.gen.go @@ -7,7 +7,7 @@ package stdhttpparamsgen import ( "bytes" - "compress/gzip" + "compress/flate" "encoding/base64" "encoding/json" "errors" @@ -1378,48 +1378,50 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H 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/9xaS2/jNhf9K8L9vlWhWHamK3UVTKdtgE4mrQNMgSALRrqOOJVEDkmnCQz994KUZD2t", - "hy3l0V1iXd7HIc+heKkdeCziLMZYSXB3IFByFks0/6xpxEP8M/tJ/+KxWGGs9J8Kn5TDQ0Jj/Z/0AoyI", - "+f2ZI7gglaDxAyRJYoOP0hOUK8picOHCksavlcey2P039BRo09SPif6RaaunL+lDdwdcMI5C0TS5S78U", - "jcYKH1BAYsOlvPCjNKns4T1jIZJYPyyc/V/gBlz4n1PU72TBnS9FPgK/b6lAH9zbfLCtQxdx7ipuqzlu", - "qJDqikTYAowNgoVtD2pRjZVdcnVnMKXxhunBIfUwm5zYBILPlzfau6JKu4cblMpao3hEATY8opDpNKwW", - "y8VSGzKOMeEUXPiwWC5WYAMnKjD5O9l8p/U5O04EiRL95AFNubpYoudVzwb8iupjeYBxJUiECoUE97ay", - "fgjnIfXMYOebZLVV1DU91YWRoQGuSRvsHAYTGcpYKrHF5M6urvHz5fJQvL2dUyNCYmI6HmN/U+xGw1g0", - "YKgSggsaUUUftSE+8ZD5CO6GhBKzwrzcTV4a2CWoNkxERKUk+HAOdoMTiT0ooobnQEA8OWIWxbeIEOR5", - "aFhSCUsVRnJQ/P0vabSWfBppdOE9Xxp7WFhOmEG4sEpCw6SsHroZsQuC4yLORfdqJV5qUGDYWoHHoAmC", - "fmZJRYSi8YP1D1WBFW+jeyOVrV5WsgJEXbrr6uLjhmxDdazCYLxNl1qrwHyKt9G1FhbZpzDX+cO0RO3W", - "eiThFmVe5/ctiufSCjOuVXCdiWhRsX4C7u1qubTPl8s7e4AYNCX3xxSbykwwK18tWfEBEh9Fl7z+llqc", - "Kq9B7iYr/q+z69KQWYW2I/TZp0wbXkR6m4lcaOv2JF5MiA9k9cpy3Mwq1aZ2sOZQ50MZvDuRbhaSOcoL", - "OkKy6z5XZ+vM+uwrVcHZVW79YjIeknsMs8VhFrCzWxjJ+qHzXfr3+rCm0rUtzyGvwdMQyAapns0hw1QI", - "U75clzHLjx9jQTt0CpkCtSHseil89nvGeIjKO90MKA1YUjNDdMXaiNePT3VcBzplXf4PUW9ff5V8I4Dr", - "Zd8pyL0J+jV414/OEL6dgsurEi4iStCnGt+o361GnxuDjpEi6s9OtLS6+QDbE20UYsfvcT2QjWPY3OCU", - "qPbTKHxO2uB6IBpBttnwaexv1B8AzgS723tmXHNzG4faCVvb+2BdlW4DoDltX3vTPONEyptAsO1DMOQG", - "5Low77z/GHF/9iq3G6Yj+DMiLy63DpVcsurpxfmIvLu5UmtE+qnrozlT60sUC8Uvcp76uJ8hF2pGoN8F", - "3B9Vyx7wJCceWn5ubnW2zmo4yqnuMAoETTpF8i3NT8qPTZdPn67OppTt1Ez5hYmod6qNUc8sD2rX1tv1", - "08Olh8LIdm0tqxdLaljbto7Z/JdotYhTBNyX2nezUK92njvjLgpPFtDK9sIDcbpv5F65wV1L9rhLyJqT", - "kXeQJyhb+qFO9YAxoMG4bgx7u53rtESYDbXKpzMjYHs7veu5ESqdNfrfrtetI1+9eT0bRvXj/VCE3k37", - "en7khn+8tm4b+CYa2LOhdAT5Olj3HmmW7btfqQrSm2FntxoARWPYjIf91cynfY2w+UA0zXsrQnAhUIq7", - "jpN9HapQqoU+M0eELwiF5C75NwAA///UsxqiOywAAA==", + "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==", } -// 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 @@ -1427,7 +1429,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) { @@ -1445,12 +1447,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() @@ -1476,3 +1478,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/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index d47eea4e87..9568743929 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" @@ -1702,52 +1702,54 @@ func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options } -// 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 @@ -1755,7 +1757,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) { @@ -1773,12 +1775,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() @@ -1804,3 +1806,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.gen.go b/internal/test/strict-server/chi/server.gen.go index cbf2515358..f54a6191ed 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -1858,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1906,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) { @@ -1924,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() @@ -1955,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/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 12172f8336..f3d5f6eaf9 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -1537,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1585,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) { @@ -1603,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() @@ -1634,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/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index 9b887e72ae..aa69ce929a 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "errors" @@ -1638,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1686,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) { @@ -1704,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() @@ -1735,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/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 076105a01a..b5294a5b54 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -1673,47 +1673,49 @@ func (sh *strictHandler) UnionExample(ctx *gin.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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1721,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) { @@ -1739,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() @@ -1770,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/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index c7ee8ecea4..e8d9dc439d 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -1763,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1811,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) { @@ -1829,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() @@ -1860,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/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 649d39e2e2..54c401bab9 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -5,7 +5,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "errors" @@ -1530,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1578,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) { @@ -1596,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() @@ -1627,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/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index b3c693a5ba..f3073a462b 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -7,7 +7,7 @@ package api import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" @@ -1757,47 +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/+xZ23LbNhN+lR38/0Wbkqbi+Ep3TSaTtmmTjmxfdXwBESsJCQkgwFKyRqOZPkSfsE/S", - "AQHqSNtSqoMn0zuJ3BP3211+S8xYrkujFSpyrDtjFp3RymH9p8+FxS8VOvL/BLrcSkNSK9Zlr7noxXvz", - "hFmsHO8X2Kh7+VwrQlWrcmMKmXOvmn1yXn/GXD7Ckvtf/7c4YF32v2wZShbuugzveWkKZPP5PNmI4ON7", - "lrARcoG2jjb8fBme4kslLQrWJVthsuKLpgZZlzmyUg2ZNxrULndSk4pwiNZH41VjkF6gibM7Y8Zqg5Zk", - "yOGYFxW2e45XdP8T5hSeUKqB3s71G62IS+VAyMEALSqCmFzwNhy4yhhtCQX0p+A95AQO7RgtSxhJ8oGx", - "69XrEAN2LGFjtC44ennRueh4PLVBxY1kXfaqvpQww2lUP9ACQKPb6uKX648fQDrgFemSk8x5UUyh5NaN", - "eIECpCLtQ6xyches9mTrwvhZRO23MZUJi8X3WovpMQqqrtuVcr/sdE5Ut/OEXQVnbTYWQWUrDVibGfCq", - "aMn5rfqs9EQBWqttfLKsrAqShltaxWo92781IrukfGEvG2hbpoITP1LWD+Xp3IlPLRac/Dh5EoBekNwP", - "hxXzR0Xh3/g5KwZxHrfOqeuRnjgY6QmQBoG8gImkETSKGwNWKuDgpBoWCE1QSSuYBcbX4o9K9OKz3Hgb", - "R59nyZqV+3QymaR1A1W2QJVr8XUQJkyWfIiZUcN1dW+bE+uy/pR8yW6/4A7UyAkjvKfMFFxuJGbT5YlG", - "+n+ZPlhjh3ZVOo0QpSuErr1xPyxk4bvLztX30BgODaxrOV4AVwJUVRSeli5lonn4+8+/AO/R5tKhAxpx", - "gko5pIUAtwi6lORJ1cDqEmi0NLPV+x/0mxDTTzH8rTq8ansSiFrrRLaJOuZiHYjmZsNRt2uhyUCr+nbH", - "BAQa6pv6nkj7cUK1IxAHHHgpT/Ua3QSchlI6PyfDTTfSVSGAFxM+dWFCb3O+XlT33K8ejUcnfskG0/+2", - "ieACWt/b54H2Bu/pSWj3GD37wnfqqbY/RPVWJtKhTj/jdKKtSA23vERC67KZj3PubQ2xxeTvC0nIuYI+", - "guIlCuADQgvvNESTrgWf4Pedfh9ElqbqlW/xp/vHjPnk1WsgS5h3wLohf8ke6/bdcaFqshk+RqRrrh4q", - "+CjSpM7iwHlK2IZxS/6Cp96KxHmW1sdrc+vzzCmK2iP58OrjR8Iu684Bqd9znwJVuPhwzqLWLmn7Sia5", - "QxbHUqDOSnO1p+WzJdUZzOVAolhwzBDbQyPhjVa5RVpfAf3LUGmChTHoT2tKGDJQvx8nCGXlCAx3DiTV", - "U6SQ4Wud2OaMt8vIIg28WY7Tx1B9cSRMX5wL0avOy/1VXh25btZWuQf6sffr2yCz7zfLg+2Me268h/N7", - "pnb2O97TO2Lcwpbv9Bzl2DMiJcAiVVahgLHkzYford6MBpawtnGhuF8t2FBzALEPIUoetXXJHj2EuPuG", - "P5Gf72gnOfECfqquqZR87ODm1t+GyOg331RSq2d6LMMLQqs4yTH+cJjvedtWtMKPg7rvN9BLdvRw9/yO", - "L49ddfOEhZPGMDArW/ipRmS6WRZOKC/chA+HaC+kzriRPkv/BAAA///qGF+njh4AAA==", -} - -// 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 @@ -1805,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) { @@ -1823,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() @@ -1854,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/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/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl index 4c6260006b..d57c2d1cd4 100644 --- a/pkg/codegen/templates/imports.tmpl +++ b/pkg/codegen/templates/imports.tmpl @@ -8,7 +8,7 @@ package {{.PackageName}} import ( "bytes" - "compress/gzip" + "compress/flate" "context" "encoding/base64" "encoding/json" diff --git a/pkg/codegen/templates/inline.tmpl b/pkg/codegen/templates/inline.tmpl index de00120502..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) { @@ -51,12 +53,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() @@ -82,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() +} From 7ba85130272d5adf26c3c36806b3190319fbba89 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 1 May 2026 10:22:04 -0700 Subject: [PATCH 263/293] Update Greptile directives (#2361) Tell Greptile to watch out for unintended dependency changes, and explain in CONTRIBUTING.md about using Greptile. --- .greptile/rules.md | 7 ++++++- CONTRIBUTING.md | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.greptile/rules.md b/.greptile/rules.md index 4384b267c7..a0cdc817ac 100644 --- a/.greptile/rules.md +++ b/.greptile/rules.md @@ -59,7 +59,12 @@ When a PR modifies a template, ask: 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. General +## 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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c4205ae6c..9790225376 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,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. From 02e0ccea08c11d4e494d6f2ebd1c594d32c762ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 08:55:37 +0000 Subject: [PATCH 264/293] Update module github.com/oapi-codegen/oapi-codegen/v2 to v2.7.0 (README.md) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 916a21dbcd..fb1c9a4ba4 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ 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/oapi-codegen/oapi-codegen/v2.6.0/configuration-schema.json +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.7.0/configuration-schema.json package: api # ... ``` From 4887ce9b3ba09d8a95dc04278f4d161b33af9229 Mon Sep 17 00:00:00 2001 From: Kotaro Inoue Date: Sun, 3 May 2026 17:09:23 +0900 Subject: [PATCH 265/293] Fix: Respect parent properties in case of merged schemas by allOf (#1415) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Respect parent properties in merging allOf schemas Signed-off-by: Kotaro Inoue * Add test case to check if parent propeties are included in the merged schema Signed-off-by: Kotaro Inoue * Make generate Signed-off-by: Kotaro Inoue * fix(codegen): only inject parent siblings into allOf merge when structural The unconditional injection of the parent (with AllOf cleared) as a final allOf member correctly merges structural siblings like properties/required, but it also forces n>=2 in mergeSchemas for pure wrappers like `{allOf: [$ref: X]}`, which previously took the n==1 fast-path and returned the referenced type. Without the fast-path those wrappers regenerate as inlined anonymous structs and lose their named-type identity (regression visible in examples/output-options/preferskipoptionalpointer). Add hasStructuralSiblings() so injection runs only when the parent has Properties, Required, or AdditionalProperties. Pure wrappers keep the fast-path. Also copy the parent's Description into the merged result — the merge does not carry Description, so it was being silently dropped. Addresses #697, #931, #1710, #1960, #2102. Partial fix for #1139 (anonymous-schema hoisting requires further work). * fix(codegen): gate allOf sibling merge behind compatibility flag Address Greptile P1 review on the previous commit: 1. append(schema.AllOf, ...) could mutate kin-openapi's backing array if the parsed slice carried spare capacity. Allocate a fresh slice with make() before appending. 2. Merging the parent's structural siblings into an allOf result is a breaking change to generated Go: a schema like {allOf: [Base], properties: {extra}} previously produced `type X = Base` (interchangeable with Base) and now produces a distinct struct (not interchangeable). Per project practice (cf. OldMergeSchemas, OldEnumConflicts, OldAliasing) gate behavior changes behind a compatibility flag. Add Compatibility.OldAllOfSiblingMerging (yaml: old-allof-sibling-merging, default false). Update configuration-schema.json with a matching description so users hit by downstream breakage can find the knob. The Description copy is gated on the same flag for consistency. Greptile also suggested narrowing hasStructuralSiblings to drop the pure-required case. Keeping Required in the trigger because that is the exact scenario issue #931 reports: a parent that adds `required: [foo]` to an allOf chain currently produces a Go type whose `Foo` field is `*string` with omitempty, ignoring the spec's required constraint. Required is structural in OAS terms — it changes field type in the generated struct — and the compatibility flag is the safety net for users whose downstream code depended on the alias output. --------- Signed-off-by: Kotaro Inoue Co-authored-by: Marcin Romaszewicz --- configuration-schema.json | 4 ++ internal/test/all_of/openapi.yaml | 11 ++++ internal/test/all_of/v1/openapi.gen.go | 39 ++++++++----- internal/test/all_of/v2/openapi.gen.go | 39 ++++++++----- internal/test/components/components.gen.go | 6 +- .../test/issues/issue-1087/deps/deps.gen.go | 17 +++++- pkg/codegen/configuration.go | 13 +++++ pkg/codegen/schema.go | 58 ++++++++++++++++++- 8 files changed, 156 insertions(+), 31 deletions(-) diff --git a/configuration-schema.json b/configuration-schema.json index 521b251ad9..8f902ca708 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -76,6 +76,10 @@ "type": "boolean", "description": "In the past, we merged schemas for `allOf` by inlining each schema within the schema list. This approach, though, is incorrect because `allOf` merges at the schema definition level, not at the resulting model level. So, new behavior merges OpenAPI specs but generates different code than we have in the past. Set OldMergeSchemas to true for the old behavior. Please see https://github.com/oapi-codegen/oapi-codegen/issues/531" }, + "old-allof-sibling-merging": { + "type": "boolean", + "description": "In the past, when a schema combined `allOf` with sibling fields at the same level (`properties`, `required`, `additionalProperties`, `description`), those siblings were silently discarded and the schema was emitted as a Go type alias to its sole `allOf` target. New behavior merges the parent's siblings with the `allOf` members so the generated type carries every field declared in the spec. This is a more accurate translation of OpenAPI semantics, but it changes the shape of generated types: a schema that previously produced `type X = Y` may now produce a distinct struct embedding Y with extra fields, which is not interchangeable with Y in downstream Go code. Set OldAllOfSiblingMerging to true to restore the prior behavior. Please see https://github.com/oapi-codegen/oapi-codegen/issues/697" + }, "old-enum-conflicts": { "type": "boolean", "description": "Enum values can generate conflicting typenames, so we've updated the code for enum generation to avoid these conflicts, but it will result in some enum types being renamed in existing code. Set OldEnumConflicts to true to revert to old behavior. Please see: Please see https://github.com/oapi-codegen/oapi-codegen/issues/549" 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 46571fcce3..2f16c10b84 100644 --- a/internal/test/all_of/v1/openapi.gen.go +++ b/internal/test/all_of/v1/openapi.gen.go @@ -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,22 +41,32 @@ type PersonWithID struct { ID int64 `json:"ID"` } +// 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"` +} + // 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{ - "lJRPb9s4EMW/yoC7R0FOsIs96Bas20BAkRpo0hziABlLI4spNWTJUQzB8HcvSMn/4BZpfRrA5OO8N7/R", - "VlW2c5aJJahiq0LVUoepXJAPlmOFxnxuVPG0VX97alSh/podb82mK7Px/MJbR140BbXLtsrT9157qlXx", - "pD5qH+QOO1KZ+oRT+bx7zlRNofLaiY7vqftWB9ABEFySzGCjpYUOuUaxfoAmCgFyDQaDAGNHGax6AZsk", - "0EA5XzL33Yp8DkluY3tTw4rAk/SeqYbVAAgvtyQvEGQwBDeLModHgo78mkBamp5fsjt4GjtBttKShy/J", - "OWxaXbVg2QzgvH3TNQXY+4ZGk6lDvmSVKRkcqULZ1StVonaZuois2F5kQYEAPU1CIC0KBEeVboZDQtEk", - "DekYGnOIIYsZLfngvQ+Tb4aXD7U+dQ7EtbOaJYNNS56AsGrjEPZaowN31upxoMV2by6I17yO5m7tG3nu", - "iKWc36VZxGON9R2KKpRm+e/fYyiahdbk48UDG5equ1+G+KilLed/Smti9NzUKPJum7vsjO1y/jskg6fK", - "+howHDlsvO0A4X9PKHQYQw6lQGVZUHNYcpxqJHKCwDaAsDhdDmTAutYT/p6C7X1F8PBQzn/KXuxfc2NT", - "xlpM/O+eggS4ifFBSiwkPZWpN/JhdHSdX+VXMXXriNFpVah/8qv8OrKB0qYEZ85gRa019TjyNckl2F/R", - "6LTOATbIAihgKG6zZYIolUGwIDHADr9RBJ86aNG5YTQUZ4ZRrKxVoRYnT8bJBGc57Beqwd6kFmKgxKlE", - "54yuksDsdfrOjWzE6n1yJt5SkOfOTt3v0u9HAAAA//8=", + "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=", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/test/all_of/v2/openapi.gen.go b/internal/test/all_of/v2/openapi.gen.go index b25d5bb90a..965051eec5 100644 --- a/internal/test/all_of/v2/openapi.gen.go +++ b/internal/test/all_of/v2/openapi.gen.go @@ -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,22 +41,32 @@ type PersonWithID struct { LastName string `json:"LastName"` } +// 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"` +} + // 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{ - "lJRPb9s4EMW/yoC7R0FOsIs96Bas20BAkRpo0hziABlLI4spNWTJUQzB8HcvSMn/4BZpfRrA5OO8N7/R", - "VlW2c5aJJahiq0LVUoepXJAPlmOFxnxuVPG0VX97alSh/podb82mK7Px/MJbR140BbXLtsrT9157qlXx", - "pD5qH+QOO1KZ+oRT+bx7zlRNofLaiY7vqftWB9ABEFySzGCjpYUOuUaxfoAmCgFyDQaDAGNHGax6AZsk", - "0EA5XzL33Yp8DkluY3tTw4rAk/SeqYbVAAgvtyQvEGQwBDeLModHgo78mkBamp5fsjt4GjtBttKShy/J", - "OWxaXbVg2QzgvH3TNQXY+4ZGk6lDvmSVKRkcqULZ1StVonaZuois2F5kQYEAPU1CIC0KBEeVboZDQtEk", - "DekYGnOIIYsZLfngvQ+Tb4aXD7U+dQ7EtbOaJYNNS56AsGrjEPZaowN31upxoMV2by6I17yO5m7tG3nu", - "iKWc36VZxGON9R2KKpRm+e/fYyiahdbk48UDG5equ1+G+KilLed/Smti9NzUKPJum7vsjO1y/jskg6fK", - "+howHDlsvO0A4X9PKHQYQw6lQGVZUHNYcpxqJHKCwDaAsDhdDmTAutYT/p6C7X1F8PBQzn/KXuxfc2NT", - "xlpM/O+eggS4ifFBSiwkPZWpN/JhdHSdX+VXMXXriNFpVah/8qv8OrKB0qYEZ85gRa019TjyNckl2F/R", - "6LTOATbIAihgKG6zZYIolUGwIDHADr9RBJ86aNG5YTQUZ4ZRrKxVoRYnT8bJBGc57Beqwd6kFmKgxKlE", - "54yuksDsdfrOjWzE6n1yJt5SkOfOTt3v0u9HAAAA//8=", + "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=", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index c80b28dc4d..85680e232c 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -319,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 @@ -371,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 } diff --git a/internal/test/issues/issue-1087/deps/deps.gen.go b/internal/test/issues/issue-1087/deps/deps.gen.go index 55a8d8e2f1..3661be9d81 100644 --- a/internal/test/issues/issue-1087/deps/deps.gen.go +++ b/internal/test/issues/issue-1087/deps/deps.gen.go @@ -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 diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index f0a549a897..f2cc4c0162 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -215,6 +215,19 @@ type CompatibilityOptions struct { // 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 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 diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index d9941381a1..2e216537f0 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -403,11 +403,48 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { // 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) + 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 Schema{}, fmt.Errorf("error merging schemas: %w", err) } 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 — @@ -1012,3 +1049,22 @@ func combinedSchemaExtensions(r *openapi3.SchemaRef) map[string]any { 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 +} From 95d614bac9537c5f8fd70f393234611ea8942b10 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sun, 3 May 2026 19:50:58 -0700 Subject: [PATCH 266/293] Update Go to 1.25.9, clean up modules, and update dependencies (#2355) Update main package Go version to 1.25.9 and remove all submodules which only existed to test on more recent versions of Go. Update almost all dependencies to their latest releases compatible with Go 1.25.9, except those which break API or behavior. Pinned github.com/dprotaso/go-yit to its existing version (latest breaks), and pinned github.com/kataras/golog v0.1.11 / github.com/kataras/pio v0.0.13 because newer combinations are incompatible with iris@v12.2.11. Updated fiber test to provide an explicit Host header, since fiber now requires it. CI lint stays on 1.26; build matrix targets 1.25 and 1.26. --- .github/workflows/ci.yml | 6 +- examples/authenticated-api/stdhttp/Makefile | 17 -- examples/authenticated-api/stdhttp/go.mod | 51 ---- examples/authenticated-api/stdhttp/go.sum | 210 -------------- examples/go.mod | 120 ++++---- examples/go.sum | 262 +++++++++--------- examples/minimal-server/stdhttp/Makefile | 17 -- examples/minimal-server/stdhttp/go.mod | 30 -- examples/minimal-server/stdhttp/go.sum | 179 ------------ examples/petstore-expanded/echo-v5/Makefile | 30 -- examples/petstore-expanded/echo-v5/go.mod | 42 --- examples/petstore-expanded/echo-v5/go.sum | 198 ------------- .../petstore-expanded/echo-v5/tools/tools.go | 8 - .../petstore-expanded/fiber/petstore_test.go | 6 +- examples/petstore-expanded/stdhttp/Makefile | 17 -- examples/petstore-expanded/stdhttp/go.mod | 41 --- examples/petstore-expanded/stdhttp/go.sum | 196 ------------- .../petstore-expanded/stdhttp/tools/tools.go | 8 - examples/streaming/stdhttp/Makefile | 36 --- go.mod | 25 +- go.sum | 56 ++-- internal/test/go.mod | 110 ++++---- internal/test/go.sum | 240 ++++++++-------- internal/test/parameters/echov5/Makefile | 45 --- internal/test/parameters/echov5/go.mod | 41 --- internal/test/parameters/echov5/go.sum | 192 ------------- internal/test/strict-server/stdhttp/Makefile | 17 -- internal/test/strict-server/stdhttp/go.mod | 42 --- internal/test/strict-server/stdhttp/go.sum | 192 ------------- 29 files changed, 427 insertions(+), 2007 deletions(-) delete mode 100644 examples/authenticated-api/stdhttp/Makefile delete mode 100644 examples/authenticated-api/stdhttp/go.mod delete mode 100644 examples/authenticated-api/stdhttp/go.sum delete mode 100644 examples/minimal-server/stdhttp/Makefile delete mode 100644 examples/minimal-server/stdhttp/go.mod delete mode 100644 examples/minimal-server/stdhttp/go.sum delete mode 100644 examples/petstore-expanded/echo-v5/Makefile delete mode 100644 examples/petstore-expanded/echo-v5/go.mod delete mode 100644 examples/petstore-expanded/echo-v5/go.sum delete mode 100644 examples/petstore-expanded/echo-v5/tools/tools.go delete mode 100644 examples/petstore-expanded/stdhttp/Makefile delete mode 100644 examples/petstore-expanded/stdhttp/go.mod delete mode 100644 examples/petstore-expanded/stdhttp/go.sum delete mode 100644 examples/petstore-expanded/stdhttp/tools/tools.go delete mode 100644 examples/streaming/stdhttp/Makefile delete mode 100644 internal/test/parameters/echov5/Makefile delete mode 100644 internal/test/parameters/echov5/go.mod delete mode 100644 internal/test/parameters/echov5/go.sum delete mode 100644 internal/test/strict-server/stdhttp/Makefile delete mode 100644 internal/test/strict-server/stdhttp/go.mod delete mode 100644 internal/test/strict-server/stdhttp/go.sum diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1988ded17..5b92f613e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,8 @@ jobs: uses: oapi-codegen/actions/.github/workflows/ci.yml@6cf35d4f044f2663dae54547ff6d426e565beb48 # v0.6.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 @@ -17,8 +19,8 @@ jobs: fail-fast: true matrix: version: - - "stable" - - "oldstable" + - "1.26" + - "1.25" steps: - name: Check out source code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/examples/authenticated-api/stdhttp/Makefile b/examples/authenticated-api/stdhttp/Makefile deleted file mode 100644 index 5ec0edd058..0000000000 --- a/examples/authenticated-api/stdhttp/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -lint: - $(GOBIN)/golangci-lint run ./... - -lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m - -generate: - go generate ./... - -test: - go test -cover ./... - -tidy: - go mod tidy - -tidy-ci: - tidied -verbose diff --git a/examples/authenticated-api/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod deleted file mode 100644 index 31580ce4bd..0000000000 --- a/examples/authenticated-api/stdhttp/go.mod +++ /dev/null @@ -1,51 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp - -go 1.24.3 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/lestrrat-go/jwx/v3 v3.0.13 - 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/testutil v1.1.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/lestrrat-go/blackmagic v1.0.4 // indirect - github.com/lestrrat-go/dsig v1.0.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/httprc/v3 v3.0.2 // indirect - github.com/lestrrat-go/option/v2 v2.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/segmentio/asm v1.2.1 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/valyala/fastjson v1.6.7 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.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 8b6ac5870d..0000000000 --- a/examples/authenticated-api/stdhttp/go.sum +++ /dev/null @@ -1,210 +0,0 @@ -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/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.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= -github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= -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/httprc/v3 v3.0.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0= -github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk= -github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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/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/testutil v1.1.0 h1:EufqpNg43acR3qzr3ObhXmWg3Sl2kwtRnUN5GYY4d5g= -github.com/oapi-codegen/testutil v1.1.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw= -github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= -github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/examples/go.mod b/examples/go.mod index cb225c3da4..d0bd535940 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,19 +1,20 @@ module github.com/oapi-codegen/oapi-codegen/v2/examples -go 1.24.3 +go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/gin-gonic/gin v1.11.0 + github.com/getkin/kin-openapi v0.137.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.12 + github.com/gofiber/fiber/v2 v2.52.13 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/kataras/iris/v12 v12.2.11 github.com/labstack/echo/v4 v4.15.1 - github.com/lestrrat-go/jwx/v3 v3.0.13 + 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 @@ -27,103 +28,104 @@ require ( ) 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.1.0 // 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.14.0 // indirect - github.com/bytedance/sonic/loader v0.3.0 // indirect - github.com/cloudwego/base64x v0.1.6 // 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.0 // 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.8 // indirect - github.com/gin-contrib/sse v1.1.0 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect + github.com/gin-contrib/sse v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/swag/jsonname v0.26.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.27.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/goccy/go-yaml v1.18.0 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect - github.com/gorilla/css v1.0.0 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/goccy/go-json v0.10.6 // indirect + github.com/goccy/go-yaml v1.19.2 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kataras/blocks v0.0.8 // 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.9 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/labstack/gommon v0.4.2 // indirect + github.com/labstack/gommon v0.5.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect - github.com/lestrrat-go/dsig v1.0.0 // 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/httprc/v3 v3.0.2 // 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.9.1 // 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.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.26 // 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/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/oasdiff/yaml3 v0.0.12 // indirect + github.com/pelletier/go-toml/v2 v2.3.0 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.54.0 // indirect - github.com/rivo/uniseg v0.4.4 // 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/segmentio/asm v1.2.1 // indirect - github.com/sirupsen/logrus v1.9.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.19.2 // indirect - github.com/tdewolff/minify/v2 v2.20.19 // indirect - github.com/tdewolff/parse/v2 v2.7.12 // 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.3.0 // 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/fastjson v1.6.7 // 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.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect - go.uber.org/mock v0.5.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.20.0 // indirect - golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect - google.golang.org/protobuf v1.36.9 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + golang.org/x/arch v0.26.0 // indirect + golang.org/x/crypto v0.50.0 // indirect + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.44.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/examples/go.sum b/examples/go.sum index df0f0883a7..37029268a1 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,40 +1,47 @@ -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/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +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.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= -github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= -github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= -github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= -github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +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/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/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +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= @@ -46,43 +53,43 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= 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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= -github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= -github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= -github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +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.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= +github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +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.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +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.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= -github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +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= @@ -92,10 +99,10 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq 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 v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +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= @@ -108,8 +115,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ 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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -127,8 +134,8 @@ 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.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= -github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= +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= @@ -139,8 +146,8 @@ 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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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= @@ -152,36 +159,38 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/labstack/echo/v5 v5.1.0 h1:MvIRydoN+p9cx/zq8Lff6YXqUW2ZaEsOMISzEGSMrBI= +github.com/labstack/echo/v5 v5.1.0/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= +github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c= +github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= -github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= -github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +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/httprc/v3 v3.0.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0= -github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk= -github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU= +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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +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.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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= -github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +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= @@ -212,8 +221,8 @@ github.com/oapi-codegen/testutil v1.1.0 h1:EufqpNg43acR3qzr3ObhXmWg3Sl2kwtRnUN5G github.com/oapi-codegen/testutil v1.1.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw= github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= +github.com/oasdiff/yaml3 v0.0.12/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= @@ -226,26 +235,25 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= -github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= -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/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/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= @@ -253,16 +261,17 @@ github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr 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.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= -github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= +github.com/speakeasy-api/openapi v1.23.0 h1:BlnHqUR/8uIs4tp3d2B4QDN03gw1/QY2R2MHg6fLhRU= +github.com/speakeasy-api/openapi v1.23.0/go.mod h1:Ih+ZzaTCCPyB2ykiDXaxhqk6jsY84ke3n5p6fobMDXk= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -270,30 +279,29 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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.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.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= -github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= -github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= -github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= -github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= +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.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= -github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +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/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= -github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +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.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= @@ -308,6 +316,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -318,26 +328,28 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn 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= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +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.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= -golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= 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= @@ -347,14 +359,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +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= @@ -371,27 +383,25 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w 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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= 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= @@ -404,16 +414,16 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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= diff --git a/examples/minimal-server/stdhttp/Makefile b/examples/minimal-server/stdhttp/Makefile deleted file mode 100644 index 5ec0edd058..0000000000 --- a/examples/minimal-server/stdhttp/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -lint: - $(GOBIN)/golangci-lint run ./... - -lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m - -generate: - go generate ./... - -test: - go test -cover ./... - -tidy: - go mod tidy - -tidy-ci: - tidied -verbose diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod deleted file mode 100644 index c5b745f440..0000000000 --- a/examples/minimal-server/stdhttp/go.mod +++ /dev/null @@ -1,30 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp - -go 1.24.3 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - -require ( - github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/getkin/kin-openapi v0.135.0 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.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 b20ab9fdc9..0000000000 --- a/examples/minimal-server/stdhttp/go.sum +++ /dev/null @@ -1,179 +0,0 @@ -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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/examples/petstore-expanded/echo-v5/Makefile b/examples/petstore-expanded/echo-v5/Makefile deleted file mode 100644 index 7eb1896df1..0000000000 --- a/examples/petstore-expanded/echo-v5/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# This module requires Go 1.25+ (for echo/v5). Skip gracefully on older versions. -GO_VERSION := $(shell go version | sed 's/.*go\([0-9]*\)\.\([0-9]*\).*/\1\2/') -GO_125_OR_LATER := $(shell [ "$(GO_VERSION)" -ge 125 ] 2>/dev/null && echo yes || echo no) - -ifeq ($(GO_125_OR_LATER),yes) - -lint: - $(GOBIN)/golangci-lint run ./... - -lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m - -generate: - go generate ./... - -test: - go test -cover ./... - -tidy: - go mod tidy - -tidy-ci: - tidied -verbose - -else - -lint generate test tidy lint-ci tidy-ci: - @echo "Skipping echo-v5 example: requires Go 1.25+ (found $(shell go version))" - -endif diff --git a/examples/petstore-expanded/echo-v5/go.mod b/examples/petstore-expanded/echo-v5/go.mod deleted file mode 100644 index 7c1c597790..0000000000 --- a/examples/petstore-expanded/echo-v5/go.mod +++ /dev/null @@ -1,42 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5 - -go 1.25.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/labstack/echo/v5 v5.0.4 - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.4.0 - github.com/oapi-codegen/testutil v1.1.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/examples/petstore-expanded/echo-v5/go.sum b/examples/petstore-expanded/echo-v5/go.sum deleted file mode 100644 index 71eb695fb0..0000000000 --- a/examples/petstore-expanded/echo-v5/go.sum +++ /dev/null @@ -1,198 +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/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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v5 v5.0.4 h1:ll3I/O8BifjMztj9dD1vx/peZQv8cR2CTUdQK6QxGGc= -github.com/labstack/echo/v5 v5.0.4/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= -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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/examples/petstore-expanded/echo-v5/tools/tools.go b/examples/petstore-expanded/echo-v5/tools/tools.go deleted file mode 100644 index 8615cb4c57..0000000000 --- a/examples/petstore-expanded/echo-v5/tools/tools.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build tools -// +build tools - -package tools - -import ( - _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" -) 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/stdhttp/Makefile b/examples/petstore-expanded/stdhttp/Makefile deleted file mode 100644 index 5ec0edd058..0000000000 --- a/examples/petstore-expanded/stdhttp/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -lint: - $(GOBIN)/golangci-lint run ./... - -lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m - -generate: - go generate ./... - -test: - go test -cover ./... - -tidy: - go mod tidy - -tidy-ci: - tidied -verbose diff --git a/examples/petstore-expanded/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod deleted file mode 100644 index 998aff9e8e..0000000000 --- a/examples/petstore-expanded/stdhttp/go.mod +++ /dev/null @@ -1,41 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp - -go 1.24.3 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../ - -require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/oapi-codegen/nethttp-middleware v1.1.2 - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.4.0 - github.com/oapi-codegen/testutil v1.1.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.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 d1e7ef7d53..0000000000 --- a/examples/petstore-expanded/stdhttp/go.sum +++ /dev/null @@ -1,196 +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/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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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/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/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= -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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/examples/petstore-expanded/stdhttp/tools/tools.go b/examples/petstore-expanded/stdhttp/tools/tools.go deleted file mode 100644 index 8615cb4c57..0000000000 --- a/examples/petstore-expanded/stdhttp/tools/tools.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build tools -// +build tools - -package tools - -import ( - _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" -) diff --git a/examples/streaming/stdhttp/Makefile b/examples/streaming/stdhttp/Makefile deleted file mode 100644 index 66f60e4a23..0000000000 --- a/examples/streaming/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/go.mod b/go.mod index b2a9469a48..5667f04195 100644 --- a/go.mod +++ b/go.mod @@ -1,35 +1,34 @@ module github.com/oapi-codegen/oapi-codegen/v2 -go 1.24.3 - -toolchain go1.24.4 +go 1.25.9 require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/speakeasy-api/openapi v1.19.2 + github.com/getkin/kin-openapi v0.137.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.33.0 - golang.org/x/text v0.34.0 - golang.org/x/tools v0.42.0 + golang.org/x/mod v0.35.0 + golang.org/x/text v0.36.0 + golang.org/x/tools v0.44.0 gopkg.in/yaml.v3 v3.0.1 ) require ( 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.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/swag/jsonname v0.26.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect + github.com/mailru/easyjson v0.9.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.12 // indirect github.com/perimeterx/marshmallow v1.1.5 // 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/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect - golang.org/x/sync v0.19.0 // indirect + golang.org/x/sync v0.20.0 // indirect ) diff --git a/go.sum b/go.sum index b20ab9fdc9..7a53485dad 100644 --- a/go.sum +++ b/go.sum @@ -5,20 +5,22 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/getkin/kin-openapi v0.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= +github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -49,8 +51,8 @@ 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +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/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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -58,8 +60,8 @@ 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= +github.com/oasdiff/yaml3 v0.0.12/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= @@ -79,12 +81,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI 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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= +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= @@ -103,8 +107,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= 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= @@ -112,13 +116,13 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +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= @@ -133,21 +137,21 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= 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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 1a1e9b4ed5..852371343d 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -1,114 +1,116 @@ module github.com/oapi-codegen/oapi-codegen/v2/internal/test -go 1.24.3 +go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/gin-gonic/gin v1.11.0 + github.com/getkin/kin-openapi v0.137.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.12 + github.com/gofiber/fiber/v2 v2.52.13 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/kataras/iris/v12 v12.2.11 github.com/labstack/echo/v4 v4.15.1 + github.com/labstack/echo/v5 v5.1.0 github.com/oapi-codegen/nullable v1.1.0 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 github.com/oapi-codegen/runtime v1.4.0 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.14.0 + 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.1.0 // 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.14.0 // indirect - github.com/bytedance/sonic/loader v0.3.0 // indirect - github.com/cloudwego/base64x v0.1.6 // 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.8 // indirect - github.com/gin-contrib/sse v1.1.0 // indirect - github.com/go-openapi/jsonpointer v0.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect + github.com/gin-contrib/sse v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/swag/jsonname v0.26.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.27.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/goccy/go-yaml v1.18.0 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect - github.com/gorilla/css v1.0.0 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/goccy/go-json v0.10.6 // indirect + github.com/goccy/go-yaml v1.19.2 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/iris-contrib/schema v0.0.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kataras/blocks v0.0.8 // 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.9 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/labstack/gommon v0.4.2 // 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.9.1 // 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.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.26 // 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/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/oasdiff/yaml3 v0.0.12 // indirect + github.com/pelletier/go-toml/v2 v2.3.0 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.54.0 // indirect - github.com/rivo/uniseg v0.2.0 // 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.9.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.19.2 // indirect + github.com/speakeasy-api/openapi v1.23.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/tdewolff/minify/v2 v2.20.19 // indirect - github.com/tdewolff/parse/v2 v2.7.12 // 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.3.0 // 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/fasttemplate v1.2.2 // indirect - github.com/valyala/tcplisten v1.0.0 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect - go.uber.org/mock v0.5.0 // indirect - golang.org/x/arch v0.20.0 // indirect - golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect - google.golang.org/protobuf v1.36.9 // 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.50.0 // indirect + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + golang.org/x/tools v0.44.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 b366040590..7f8a1dd512 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -1,38 +1,45 @@ -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/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +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.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= -github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= -github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= -github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= -github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +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/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= @@ -44,43 +51,43 @@ github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0H github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= 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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/getkin/kin-openapi v0.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= -github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= -github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= -github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +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.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= +github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +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.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +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.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= -github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -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/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +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= @@ -90,10 +97,10 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq 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 v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU= -github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +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= @@ -106,8 +113,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ 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.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -125,8 +132,8 @@ 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.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM= -github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg= +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= @@ -137,8 +144,8 @@ 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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +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= @@ -150,22 +157,24 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +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.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +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.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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= -github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +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= @@ -188,8 +197,8 @@ github.com/oapi-codegen/testutil v1.1.0 h1:EufqpNg43acR3qzr3ObhXmWg3Sl2kwtRnUN5G github.com/oapi-codegen/testutil v1.1.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw= github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= +github.com/oasdiff/yaml3 v0.0.12/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= @@ -202,36 +211,36 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= -github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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.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.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= -github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= +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= @@ -245,28 +254,27 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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.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.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo= -github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM= -github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ= -github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= -github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= -github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= +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.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= -github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +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/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.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= @@ -281,6 +289,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo 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= @@ -291,23 +301,25 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn 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= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +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.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= -golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= -golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= 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= @@ -317,14 +329,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= 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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +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= @@ -341,26 +353,24 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w 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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= 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= @@ -373,16 +383,16 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +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/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.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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= diff --git a/internal/test/parameters/echov5/Makefile b/internal/test/parameters/echov5/Makefile deleted file mode 100644 index 54df0d106e..0000000000 --- a/internal/test/parameters/echov5/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -GO_VERSION := $(shell go version | sed -E 's/.*go([0-9]+\.[0-9]+).*/\1/') -MIN_VERSION := 1.25 -VERSION_OK := $(shell printf '%s\n%s' '$(MIN_VERSION)' '$(GO_VERSION)' | sort -V | head -1 | grep -q '^$(MIN_VERSION)$$' && echo yes || echo no) - -lint: -ifeq ($(VERSION_OK),yes) - $(GOBIN)/golangci-lint run ./... -else - @echo "Skipping lint: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif - -lint-ci: -ifeq ($(VERSION_OK),yes) - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m -else - @echo "Skipping lint-ci: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif - -generate: -ifeq ($(VERSION_OK),yes) - go generate ./... -else - @echo "Skipping generate: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif - -test: -ifeq ($(VERSION_OK),yes) - go test -cover ./... -else - @echo "Skipping test: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif - -tidy: -ifeq ($(VERSION_OK),yes) - go mod tidy -else - @echo "Skipping tidy: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif - -tidy-ci: -ifeq ($(VERSION_OK),yes) - tidied -verbose -else - @echo "Skipping tidy-ci: requires Go >= $(MIN_VERSION), have $(GO_VERSION)" -endif diff --git a/internal/test/parameters/echov5/go.mod b/internal/test/parameters/echov5/go.mod deleted file mode 100644 index ee133844b5..0000000000 --- a/internal/test/parameters/echov5/go.mod +++ /dev/null @@ -1,41 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5 - -go 1.25.0 - -replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../ - -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen - -require ( - github.com/getkin/kin-openapi v0.135.0 - github.com/labstack/echo/v5 v5.0.4 - github.com/oapi-codegen/runtime v1.4.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/internal/test/parameters/echov5/go.sum b/internal/test/parameters/echov5/go.sum deleted file mode 100644 index 67fc9e2b1b..0000000000 --- a/internal/test/parameters/echov5/go.sum +++ /dev/null @@ -1,192 +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/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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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/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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v5 v5.0.4 h1:ll3I/O8BifjMztj9dD1vx/peZQv8cR2CTUdQK6QxGGc= -github.com/labstack/echo/v5 v5.0.4/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= -github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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.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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/strict-server/stdhttp/Makefile b/internal/test/strict-server/stdhttp/Makefile deleted file mode 100644 index 5ec0edd058..0000000000 --- a/internal/test/strict-server/stdhttp/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -lint: - $(GOBIN)/golangci-lint run ./... - -lint-ci: - $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m - -generate: - go generate ./... - -test: - go test -cover ./... - -tidy: - go mod tidy - -tidy-ci: - tidied -verbose diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod deleted file mode 100644 index 4f1b9151ca..0000000000 --- a/internal/test/strict-server/stdhttp/go.mod +++ /dev/null @@ -1,42 +0,0 @@ -module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp - -go 1.24.3 - -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.135.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.4.0 - github.com/oapi-codegen/testutil v1.1.0 - github.com/stretchr/testify v1.11.1 -) - -require ( - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // 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.22.4 // indirect - github.com/go-openapi/swag/jsonname v0.25.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.9 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/speakeasy-api/jsonpath v0.6.3 // indirect - github.com/speakeasy-api/openapi v1.19.2 // indirect - github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.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 06ee6318c1..0000000000 --- a/internal/test/strict-server/stdhttp/go.sum +++ /dev/null @@ -1,192 +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/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/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/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.135.0 h1:751SjYfbiwqukYuVjwYEIKNfrSwS5YpA7DZnKSwQgtg= -github.com/getkin/kin-openapi v0.135.0/go.mod h1:6dd5FJl6RdX4usBtFBaQhk9q62Yb2J0Mk5IhUO/QqFI= -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -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/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/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/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/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.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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -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/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/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= -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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.9 h1:rWPrKccrdUm8J0F3sGuU+fuh9+1K/RdJlWF7O/9yw2g= -github.com/oasdiff/yaml3 v0.0.9/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/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.19.2 h1:md90tE71/M8jS3cuRlsuWP5Aed4xoG5PSRvXeZgCv/M= -github.com/speakeasy-api/openapi v1.19.2/go.mod h1:UfKa7FqE4jgexJZuj51MmdHAFGmDv0Zaw3+yOd81YKU= -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.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/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= -github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= -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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -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.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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= From c346d1273edbe2f6b886fc6aeeef982c7306082b Mon Sep 17 00:00:00 2001 From: Viktoras Makauskas Date: Tue, 5 May 2026 00:35:15 +0300 Subject: [PATCH 267/293] fix: properly handle quotes in content-type when generating server code (#1929) fixes #1799 OpenAPI media types may contain characters that require escaping in Go string literals, for example, application/ld+json; profile="https://..." which the templates were emitting verbatim, producing invalid Go. PR #2217 had a partial fix for this, and this PR fixes the other cases. Adds a regression test under internal/test/issues/issue1799/ covering chi, client, echo, fiber, gin, gorilla, iris, and std-http generation modes with a spec containing a quoted media-type parameter. Co-authored-by: Marcin Romaszewicz --- examples/go.sum | 54 ++ internal/test/go.sum | 51 ++ internal/test/issues/issue1799/chi/out.gen.go | 518 +++++++++++++ .../test/issues/issue1799/client/out.gen.go | 686 ++++++++++++++++++ .../issues/issue1799/config-chi-server.yaml | 8 + .../test/issues/issue1799/config-client.yaml | 7 + .../issues/issue1799/config-echo-server.yaml | 8 + .../issues/issue1799/config-fiber-server.yaml | 8 + .../issues/issue1799/config-gin-server.yaml | 8 + .../issue1799/config-gorilla-server.yaml | 8 + .../issues/issue1799/config-iris-server.yaml | 8 + .../issue1799/config-std-http-server.yaml | 8 + .../test/issues/issue1799/echo/out.gen.go | 369 ++++++++++ .../test/issues/issue1799/fiber/out.gen.go | 380 ++++++++++ internal/test/issues/issue1799/generate.go | 10 + internal/test/issues/issue1799/gin/out.gen.go | 422 +++++++++++ .../test/issues/issue1799/gorilla/out.gen.go | 489 +++++++++++++ .../test/issues/issue1799/iris/out.gen.go | 338 +++++++++ internal/test/issues/issue1799/spec.yaml | 51 ++ .../test/issues/issue1799/std-http/out.gen.go | 493 +++++++++++++ pkg/codegen/templates/client.tmpl | 2 +- pkg/codegen/templates/strict/strict-echo.tmpl | 2 +- .../templates/strict/strict-echo5.tmpl | 2 +- .../strict/strict-fiber-interface.tmpl | 2 +- .../templates/strict/strict-fiber.tmpl | 2 +- pkg/codegen/templates/strict/strict-gin.tmpl | 2 +- pkg/codegen/templates/strict/strict-http.tmpl | 2 +- .../templates/strict/strict-interface.tmpl | 2 +- .../strict/strict-iris-interface.tmpl | 2 +- pkg/codegen/templates/strict/strict-iris.tmpl | 2 +- 30 files changed, 3934 insertions(+), 10 deletions(-) create mode 100644 internal/test/issues/issue1799/chi/out.gen.go create mode 100644 internal/test/issues/issue1799/client/out.gen.go create mode 100644 internal/test/issues/issue1799/config-chi-server.yaml create mode 100644 internal/test/issues/issue1799/config-client.yaml create mode 100644 internal/test/issues/issue1799/config-echo-server.yaml create mode 100644 internal/test/issues/issue1799/config-fiber-server.yaml create mode 100644 internal/test/issues/issue1799/config-gin-server.yaml create mode 100644 internal/test/issues/issue1799/config-gorilla-server.yaml create mode 100644 internal/test/issues/issue1799/config-iris-server.yaml create mode 100644 internal/test/issues/issue1799/config-std-http-server.yaml create mode 100644 internal/test/issues/issue1799/echo/out.gen.go create mode 100644 internal/test/issues/issue1799/fiber/out.gen.go create mode 100644 internal/test/issues/issue1799/generate.go create mode 100644 internal/test/issues/issue1799/gin/out.gen.go create mode 100644 internal/test/issues/issue1799/gorilla/out.gen.go create mode 100644 internal/test/issues/issue1799/iris/out.gen.go create mode 100644 internal/test/issues/issue1799/spec.yaml create mode 100644 internal/test/issues/issue1799/std-http/out.gen.go diff --git a/examples/go.sum b/examples/go.sum index 37029268a1..619b56272c 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -20,6 +20,7 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D 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/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= @@ -27,6 +28,8 @@ github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoO 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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= @@ -34,17 +37,25 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ 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/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/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/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= 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/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -65,8 +76,10 @@ 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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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 v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -84,12 +97,16 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 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= @@ -119,16 +136,20 @@ 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/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= 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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= 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/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -140,6 +161,8 @@ 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/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo= +github.com/kataras/neffos v0.0.24-0.20240408172741-99c879ba0ede/go.mod h1:i0dtcTbpnw1lqIbojYtGtZlu6gDWPxJ4Xl2eJ6oQ1bE= 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= @@ -179,6 +202,7 @@ github.com/lestrrat-go/jwx/v3 v3.1.0 h1:AyyLtxc0QM75F75JroWgt1phwC7X+wOb3XKhH7XB 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M= @@ -189,6 +213,7 @@ github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw 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/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 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= @@ -200,6 +225,9 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G 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/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 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= @@ -235,17 +263,23 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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 v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 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/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= @@ -260,6 +294,8 @@ 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/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -283,6 +319,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl 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/argp v0.0.0-20260424074207-decde4f86440/go.mod h1:t4IfmOfK1WpBPd456pTdSB4f+BuMp6CUGnV7CBzduxk= 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= @@ -290,6 +327,9 @@ github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLB 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/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= @@ -302,6 +342,7 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT 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/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 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= @@ -310,6 +351,9 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9N github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 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= @@ -322,12 +366,16 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJx 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/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= 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= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= 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= @@ -385,8 +433,10 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= 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.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= 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= @@ -402,10 +452,13 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/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= @@ -438,3 +491,4 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/test/go.sum b/internal/test/go.sum index 7f8a1dd512..9a5458f62f 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -20,6 +20,7 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D 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/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= @@ -27,6 +28,8 @@ github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoO 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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= @@ -34,15 +37,22 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ 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/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/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/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -63,8 +73,10 @@ 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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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 v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -82,6 +94,9 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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= @@ -117,6 +132,7 @@ 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/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= 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= @@ -127,6 +143,8 @@ github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk 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/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -138,6 +156,8 @@ 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/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo= +github.com/kataras/neffos v0.0.24-0.20240408172741-99c879ba0ede/go.mod h1:i0dtcTbpnw1lqIbojYtGtZlu6gDWPxJ4Xl2eJ6oQ1bE= 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= @@ -163,6 +183,7 @@ 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M= @@ -173,6 +194,7 @@ github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw 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/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 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= @@ -184,6 +206,9 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G 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/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 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= @@ -211,17 +236,23 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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 v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 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/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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= @@ -234,6 +265,8 @@ github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiy github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= 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/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -258,6 +291,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl 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/argp v0.0.0-20260424074207-decde4f86440/go.mod h1:t4IfmOfK1WpBPd456pTdSB4f+BuMp6CUGnV7CBzduxk= 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= @@ -265,6 +299,9 @@ github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLB 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/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= @@ -275,6 +312,7 @@ github.com/valyala/fasthttp v1.70.0 h1:LAhMGcWk13QZWm85+eg8ZBNbrq5mnkWFGbHMUJHId 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/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 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= @@ -283,6 +321,9 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9N github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 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= @@ -295,12 +336,16 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJx 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/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= 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= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= 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= @@ -355,8 +400,10 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= 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.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= 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= @@ -371,10 +418,13 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/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= @@ -407,3 +457,4 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 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..4e70c70ddb --- /dev/null +++ b/internal/test/issues/issue1799/client/out.gen.go @@ -0,0 +1,686 @@ +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl index 74407a3ebf..1f02997e1f 100644 --- a/pkg/codegen/templates/client.tmpl +++ b/pkg/codegen/templates/client.tmpl @@ -158,7 +158,7 @@ func New{{$opid}}Request{{.Suffix}}(server string{{genParamArgs $pathParams}}{{i {{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}} diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl index 7981c76b9e..0683c15e30 100644 --- a/pkg/codegen/templates/strict/strict-echo.tmpl +++ b/pkg/codegen/templates/strict/strict-echo.tmpl @@ -31,7 +31,7 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-echo5.tmpl b/pkg/codegen/templates/strict/strict-echo5.tmpl index a7e617c1ae..687dd57a8b 100644 --- a/pkg/codegen/templates/strict/strict-echo5.tmpl +++ b/pkg/codegen/templates/strict/strict-echo5.tmpl @@ -31,7 +31,7 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index 2a1905066e..a88607a88b 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -95,7 +95,7 @@ {{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 | toGoString}}{{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)) diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl index 786a11aef8..0bdc9af82d 100644 --- a/pkg/codegen/templates/strict/strict-fiber.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber.tmpl @@ -32,7 +32,7 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl index 167bff762e..ed2e561a51 100644 --- a/pkg/codegen/templates/strict/strict-gin.tmpl +++ b/pkg/codegen/templates/strict/strict-gin.tmpl @@ -76,7 +76,7 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl index 16a902456c..062e5459e4 100644 --- a/pkg/codegen/templates/strict/strict-http.tmpl +++ b/pkg/codegen/templates/strict/strict-http.tmpl @@ -48,7 +48,7 @@ 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 { diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index 237f668b1e..206cc88bd1 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -129,7 +129,7 @@ _, err = w.Write([]byte(form.Encode())) return err {{else -}} - 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 | toGoString}}{{else}}response.ContentType{{end}}) + 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)) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index dbef961d3e..e48d7ab6d3 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -95,7 +95,7 @@ {{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 | toGoString}}{{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)) diff --git a/pkg/codegen/templates/strict/strict-iris.tmpl b/pkg/codegen/templates/strict/strict-iris.tmpl index f6342ee37a..5195c251b0 100644 --- a/pkg/codegen/templates/strict/strict-iris.tmpl +++ b/pkg/codegen/templates/strict/strict-iris.tmpl @@ -31,7 +31,7 @@ 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 { From 52acac49c83ad3c846827aaaf2322350b39637ff Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Sat, 16 May 2026 09:00:49 -0700 Subject: [PATCH 268/293] Don't generate constants for undefined scopes (#2372) A spec that lists a scheme under top-level or operation `security:` without declaring it in `components/securitySchemes` previously emitted a constant like `Api_keyScopes apiKeyContextKey = "api_key.Scopes"` while the `apiKeyContextKey` type itself was never generated. The output failed to compile with `undefined: apiKeyContextKey`, and per-framework middleware templates emitted matching dangling `context.WithValue(ctx, Api_keyScopes, ...)` references when servers were generated. Filter operation `SecurityDefinitions` against the set of schemes actually defined in `components/securitySchemes` in `OperationDefinitions`. Both the constants block and the per-framework middleware now stay in sync with the types that get emitted, so generated code compiles whether or not the spec defines every referenced scheme. Closes: #2367 Co-authored-by: Claude Opus 4.7 (1M context) --- examples/go.sum | 54 ------ internal/test/go.sum | 51 ----- internal/test/issues/issue-2367/api.gen.go | 174 ++++++++++++++++++ internal/test/issues/issue-2367/cfg.yaml | 7 + internal/test/issues/issue-2367/generate.go | 3 + .../test/issues/issue-2367/issue_2367_test.go | 23 +++ internal/test/issues/issue-2367/spec.yaml | 13 ++ pkg/codegen/operations.go | 26 +++ 8 files changed, 246 insertions(+), 105 deletions(-) create mode 100644 internal/test/issues/issue-2367/api.gen.go create mode 100644 internal/test/issues/issue-2367/cfg.yaml create mode 100644 internal/test/issues/issue-2367/generate.go create mode 100644 internal/test/issues/issue-2367/issue_2367_test.go create mode 100644 internal/test/issues/issue-2367/spec.yaml diff --git a/examples/go.sum b/examples/go.sum index 619b56272c..37029268a1 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -20,7 +20,6 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D 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/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= @@ -28,8 +27,6 @@ github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoO 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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= @@ -37,25 +34,17 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ 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/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/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/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= 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/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -76,10 +65,8 @@ 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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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 v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -97,16 +84,12 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 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= @@ -136,20 +119,16 @@ 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/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= 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/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= 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/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= -github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -161,8 +140,6 @@ 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/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo= -github.com/kataras/neffos v0.0.24-0.20240408172741-99c879ba0ede/go.mod h1:i0dtcTbpnw1lqIbojYtGtZlu6gDWPxJ4Xl2eJ6oQ1bE= 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= @@ -202,7 +179,6 @@ github.com/lestrrat-go/jwx/v3 v3.1.0 h1:AyyLtxc0QM75F75JroWgt1phwC7X+wOb3XKhH7XB 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M= @@ -213,7 +189,6 @@ github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw 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/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 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= @@ -225,9 +200,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G 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/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= -github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 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= @@ -263,23 +235,17 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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 v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 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/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= @@ -294,8 +260,6 @@ 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/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -319,7 +283,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl 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/argp v0.0.0-20260424074207-decde4f86440/go.mod h1:t4IfmOfK1WpBPd456pTdSB4f+BuMp6CUGnV7CBzduxk= 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= @@ -327,9 +290,6 @@ github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLB 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/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= @@ -342,7 +302,6 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT 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/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 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= @@ -351,9 +310,6 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9N github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 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= @@ -366,16 +322,12 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJx 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/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= 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= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= 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= @@ -433,10 +385,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= 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.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= 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= @@ -452,13 +402,10 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= -golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= -golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/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= @@ -491,4 +438,3 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/test/go.sum b/internal/test/go.sum index 9a5458f62f..7f8a1dd512 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -20,7 +20,6 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D 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/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= @@ -28,8 +27,6 @@ github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoO 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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= @@ -37,22 +34,15 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ 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/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/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/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= 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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -73,10 +63,8 @@ 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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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 v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -94,9 +82,6 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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= @@ -132,7 +117,6 @@ 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/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= 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= @@ -143,8 +127,6 @@ github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk 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/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= -github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -156,8 +138,6 @@ 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/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo= -github.com/kataras/neffos v0.0.24-0.20240408172741-99c879ba0ede/go.mod h1:i0dtcTbpnw1lqIbojYtGtZlu6gDWPxJ4Xl2eJ6oQ1bE= 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= @@ -183,7 +163,6 @@ 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M= @@ -194,7 +173,6 @@ github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw 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/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 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= @@ -206,9 +184,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G 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/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= -github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 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= @@ -236,23 +211,17 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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 v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 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/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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= @@ -265,8 +234,6 @@ github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiy github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= 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/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -291,7 +258,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl 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/argp v0.0.0-20260424074207-decde4f86440/go.mod h1:t4IfmOfK1WpBPd456pTdSB4f+BuMp6CUGnV7CBzduxk= 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= @@ -299,9 +265,6 @@ github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLB 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/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= @@ -312,7 +275,6 @@ github.com/valyala/fasthttp v1.70.0 h1:LAhMGcWk13QZWm85+eg8ZBNbrq5mnkWFGbHMUJHId 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/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 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= @@ -321,9 +283,6 @@ github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9N github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 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= @@ -336,16 +295,12 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJx 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/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= 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= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= 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= @@ -400,10 +355,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= 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.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= 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= @@ -418,13 +371,10 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= -golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= -golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/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= @@ -457,4 +407,3 @@ 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= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 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/pkg/codegen/operations.go b/pkg/codegen/operations.go index 94b6911c71..736a8ea1b5 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -309,6 +309,21 @@ 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 is the `operationId` field from the OpenAPI Specification, after going through a `nameNormalizer`, and will be used to generate function names @@ -745,6 +760,16 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { 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{} @@ -881,6 +906,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { opDef.SecurityDefinitions = DescribeSecurityDefinition(swagger.Security) } + opDef.SecurityDefinitions = filterOutUndefinedSecuritySchemes(opDef.SecurityDefinitions, definedSecuritySchemes) if op.RequestBody != nil { opDef.BodyRequired = op.RequestBody.Value.Required From c699d899edec9f63416b901fc9e71b8f0a67b14b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 12:54:18 +0000 Subject: [PATCH 269/293] chore(deps): update oapi-codegen/actions action to v0.8.0 (.github/workflows) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b92f613e1..ea194c6bfc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ permissions: contents: read jobs: build: - uses: oapi-codegen/actions/.github/workflows/ci.yml@6cf35d4f044f2663dae54547ff6d426e565beb48 # v0.6.0 + 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. From 6ed13af79d19a82c49f75e24cf4a4e335ff5482e Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 17 May 2026 14:16:56 +0100 Subject: [PATCH 270/293] chore(renovate): correct path for `go.sum` --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 8ac4d6e63c..56b79e9506 100644 --- a/renovate.json +++ b/renovate.json @@ -56,7 +56,7 @@ "description": "", "matchFileNames": [ "**/*/go.mod", - "**/*.go.sum" + "**/*/go.sum" ], "postUpgradeTasks": { "commands": [ From f73fd3f66581af3667b45a8c0e9de81a10077491 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 17 May 2026 14:17:11 +0100 Subject: [PATCH 271/293] chore(renovate): add explicit parent path Instead of trying to make the `matchFileNames` match both, we can use a new pattern. --- renovate.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/renovate.json b/renovate.json index 56b79e9506..49ffad5a4d 100644 --- a/renovate.json +++ b/renovate.json @@ -55,6 +55,8 @@ { "description": "", "matchFileNames": [ + "go.mod", + "go.sum", "**/*/go.mod", "**/*/go.sum" ], From fd9959acc42c0a3625a22dbc9e40354e43163981 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 17 May 2026 14:18:10 +0100 Subject: [PATCH 272/293] chore(renovate): add missing description --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 49ffad5a4d..fd7d48d244 100644 --- a/renovate.json +++ b/renovate.json @@ -53,7 +53,7 @@ "enabled": false }, { - "description": "", + "description": "Run `make tidy` after updates to Go modules", "matchFileNames": [ "go.mod", "go.sum", From 5e6d4e013e8051d5fb93feddc1e3c55b079fb985 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 13:23:28 +0000 Subject: [PATCH 273/293] fix(deps): update module github.com/getkin/kin-openapi to v0.138.0 (go.mod) --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index d0bd535940..0929c287ca 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.137.0 + github.com/getkin/kin-openapi v0.138.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 diff --git a/examples/go.sum b/examples/go.sum index 37029268a1..c93ef703ff 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -57,8 +57,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= -github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= +github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= 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= diff --git a/go.mod b/go.mod index 5667f04195..effd606543 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.25.9 require ( - github.com/getkin/kin-openapi v0.137.0 + github.com/getkin/kin-openapi v0.138.0 github.com/speakeasy-api/openapi v1.23.0 github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v3 v3.0.4 diff --git a/go.sum b/go.sum index 7a53485dad..bb5bf51008 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= -github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= +github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 852371343d..e254ec9cfd 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.137.0 + github.com/getkin/kin-openapi v0.138.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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 7f8a1dd512..c416f70590 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -55,8 +55,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= -github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= +github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= 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= From 3f74c6c79208d610e36d2fe9dba98f00430623bd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 12:57:35 +0000 Subject: [PATCH 274/293] chore(deps): update dessant/label-actions action to v5.0.1 (.github/workflows) --- .github/workflows/label-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml index 9e854222e2..94b3e9063c 100644 --- a/.github/workflows/label-actions.yml +++ b/.github/workflows/label-actions.yml @@ -18,6 +18,6 @@ jobs: reaction: runs-on: ubuntu-latest steps: - - uses: dessant/label-actions@9e5fd757ffe1e065abf55e9f74d899dbe012922a # v5.0.0 + - uses: dessant/label-actions@e86a1759593319d037dab008f3124abeb786cdf9 # v5.0.1 with: github-token: ${{ github.token }} From 4901c8e75454fe4fe9e11a24324a2c0a2341078e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 13:26:52 +0000 Subject: [PATCH 275/293] fix(deps): update module golang.org/x/tools to v0.45.0 (go.mod) --- examples/go.mod | 12 ++++++------ examples/go.sum | 24 ++++++++++++------------ go.mod | 4 ++-- go.sum | 16 ++++++++-------- internal/test/go.mod | 12 ++++++------ internal/test/go.sum | 24 ++++++++++++------------ 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 0929c287ca..29e5f1b250 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -115,15 +115,15 @@ require ( 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.50.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.35.0 // indirect - golang.org/x/net v0.53.0 // 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.43.0 // indirect - golang.org/x/text v0.36.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.44.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/examples/go.sum b/examples/go.sum index c93ef703ff..1b42319a6a 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -339,8 +339,8 @@ 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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +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= @@ -348,8 +348,8 @@ golang.org/x/lint v0.0.0-20241112194109-818c5a804067/go.mod h1:3xt1FjdF8hUf6vQPI 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.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +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= @@ -359,8 +359,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +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= @@ -383,16 +383,16 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w 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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +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.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +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= @@ -400,8 +400,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn 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.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +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= diff --git a/go.mod b/go.mod index effd606543..2ba1579c35 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( 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.35.0 + golang.org/x/mod v0.36.0 golang.org/x/text v0.36.0 - golang.org/x/tools v0.44.0 + golang.org/x/tools v0.45.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index bb5bf51008..a5d0cbe446 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +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= @@ -116,8 +116,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ 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.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +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= @@ -137,8 +137,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +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= @@ -150,8 +150,8 @@ golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= 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.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +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= diff --git a/internal/test/go.mod b/internal/test/go.mod index e254ec9cfd..ef5fde5273 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -102,14 +102,14 @@ require ( github.com/yosssi/ace v0.0.5 // indirect go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect golang.org/x/arch v0.26.0 // indirect - golang.org/x/crypto v0.50.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.35.0 // indirect - golang.org/x/net v0.53.0 // 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.43.0 // indirect - golang.org/x/text v0.36.0 // indirect - golang.org/x/tools v0.44.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 c416f70590..2ac681d838 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -312,14 +312,14 @@ 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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +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.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +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= @@ -329,8 +329,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +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= @@ -353,24 +353,24 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w 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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +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.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +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.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +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= From b75036be33cab2c433104082dcedb95928308efb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 04:26:58 +0000 Subject: [PATCH 276/293] chore(deps): update actions/labeler action to v6.1.0 (.github/workflows) --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index c7eb2865f1..d0a8024b05 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -12,4 +12,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 From 2fd3d0d0dbaf4fcb9be6312401d1cab4a50c6522 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 11:35:09 +0000 Subject: [PATCH 277/293] chore(deps): update actions/upload-artifact action to v7.0.1 (.github/workflows) --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 459dd315e0..570ece5a14 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: SARIF file path: results.sarif From 3df18d451c3bb9175f2c59c25b7be9b686426320 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 11:35:14 +0000 Subject: [PATCH 278/293] chore(deps): update actions/setup-go action to v6.4.0 (.github/workflows) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea194c6bfc..d1eced9ef1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: ${{ matrix.version }} From 31185d09c65b8291cf4412a54fcb7cc04f5647db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 14:10:51 +0000 Subject: [PATCH 279/293] chore(deps): update github/codeql-action action to v4.35.5 (.github/workflows) --- .github/workflows/govulncheck.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 6be0b7d905..742c902f26 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -29,7 +29,7 @@ jobs: # ... 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@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 + uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: sarif_file: govulncheck.sarif category: govulncheck diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 570ece5a14..24990b1090 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,6 +41,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 + uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: sarif_file: results.sarif From c6c3f920e0f3a4760a5f15913fba3cb33cd23459 Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sun, 17 May 2026 15:13:32 +0100 Subject: [PATCH 280/293] lint: migrate to `golangci-lint`'s install script on `main` Via [0], otherwise downloads fails with: ``` golangci/golangci-lint err hash_sha256_verify checksum for '/tmp/.../golangci-lint-2.12.2-linux-amd64.tar.gz' did not verify ``` [0]: https://redirect.github.com/golangci/golangci-lint/issues/6572#issuecomment-4400895705 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f09a336c11..9901df12d5 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) v2.10.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/main/install.sh | sh -s -- -b $(GOBIN) v2.10.1 .PHONY: tools tools: $(GOBIN)/golangci-lint From 75ecc2c8f1ec3c5b4eaf5cbb07152832b247c030 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 14:22:50 +0000 Subject: [PATCH 281/293] chore(deps): update module github.com/golangci/golangci-lint to v2.12.2 (makefile) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9901df12d5..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/main/install.sh | sh -s -- -b $(GOBIN) v2.10.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 From df17a79a4c3baded13c218a860375b39c8a40976 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 10:40:29 +0000 Subject: [PATCH 282/293] chore(deps): update release-drafter/release-drafter action to v7.3.0 (.github/workflows) --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index ec1c0685ae..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@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7.2.0 + - uses: release-drafter/release-drafter@c2e2804cc59f45f57076a99af580d0fedb697927 # v7.3.0 with: name: next tag: next From d4ab4d91e0e0e62e94e31ca79d99293e2c83d130 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 13:59:43 +0000 Subject: [PATCH 283/293] fix(deps): update module golang.org/x/text to v0.37.0 (go.mod) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2ba1579c35..8cc1220b39 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( 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.36.0 + golang.org/x/text v0.37.0 golang.org/x/tools v0.45.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index a5d0cbe446..dfdae7c835 100644 --- a/go.sum +++ b/go.sum @@ -145,8 +145,8 @@ 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.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +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= From 84bfb1b48778af039f9bfbd80774a1c09028ff2c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 16:42:22 +0000 Subject: [PATCH 284/293] chore(deps): update dessant/label-actions action to v5.0.2 (.github/workflows) --- .github/workflows/label-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml index 94b3e9063c..d83815765f 100644 --- a/.github/workflows/label-actions.yml +++ b/.github/workflows/label-actions.yml @@ -18,6 +18,6 @@ jobs: reaction: runs-on: ubuntu-latest steps: - - uses: dessant/label-actions@e86a1759593319d037dab008f3124abeb786cdf9 # v5.0.1 + - uses: dessant/label-actions@809e0f9bc11ce08744e7ccac7cd10621d00aba2f # v5.0.2 with: github-token: ${{ github.token }} From 8c4029a30e20b52c6494de13422fd0f0c2d896f1 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 19 May 2026 09:00:21 -0700 Subject: [PATCH 285/293] Extend deepObject testing to include unicode (#2381) Closes #2378 Since we test nearly everything in ASCII, we missed some failures in runtime around marshaling parameters. Extend the deepObject test to catch issues if they resurface. Co-authored-by: Claude Opus 4.7 (1M context) --- examples/go.mod | 2 +- examples/go.sum | 6 +++-- internal/test/go.mod | 2 +- internal/test/go.sum | 4 ++-- .../test/parameters/param_roundtrip_test.go | 23 +++++++++++++++++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 29e5f1b250..2132ce7510 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -21,7 +21,7 @@ require ( github.com/oapi-codegen/iris-middleware v1.0.5 github.com/oapi-codegen/nethttp-middleware v1.1.2 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.4.0 + 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 diff --git a/examples/go.sum b/examples/go.sum index 1b42319a6a..b8ab3ad12e 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -215,8 +215,10 @@ github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq github.com/oapi-codegen/iris-middleware v1.0.5/go.mod h1:/ysgvbjWyhfDAouIeUOjzIv+zsXfaIXlAQrsOU9/Kyo= github.com/oapi-codegen/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA= github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4= -github.com/oapi-codegen/runtime v1.4.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= +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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/internal/test/go.mod b/internal/test/go.mod index ef5fde5273..8c270dbbd4 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -16,7 +16,7 @@ require ( github.com/labstack/echo/v5 v5.1.0 github.com/oapi-codegen/nullable v1.1.0 github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000 - github.com/oapi-codegen/runtime v1.4.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 diff --git a/internal/test/go.sum b/internal/test/go.sum index 2ac681d838..742c531bcf 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -191,8 +191,8 @@ 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.0 h1:KLOSFOp7UzkbS7Cs1ms6NBEKYr0WmH2wZG0KKbd2er4= -github.com/oapi-codegen/runtime v1.4.0/go.mod h1:5sw5fxCDmnOzKNYmkVNF8d34kyUeejJEY8HNT2WaPec= +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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= diff --git a/internal/test/parameters/param_roundtrip_test.go b/internal/test/parameters/param_roundtrip_test.go index e0b2fc93d1..2bca8801e3 100644 --- a/internal/test/parameters/param_roundtrip_test.go +++ b/internal/test/parameters/param_roundtrip_test.go @@ -392,6 +392,29 @@ func testImpl(t *testing.T, handler http.Handler) { 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) { }) From 28b47cafa3b89e08d4df203aebbfdb5d955da15a Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 19 May 2026 09:21:38 -0700 Subject: [PATCH 286/293] Echo V5 now uses the generic test framework (#2382) When I updated to Go 1.25 and un-moduled the echo-v5 code, I left behind the special-cased test for echo-v5 which existed due to module boundaries. Since those modules don't exist anymore, we can remove the special casing. Co-authored-by: Claude Opus 4.7 (1M context) --- .../test/parameters/echov5/client.cfg.yaml | 5 - internal/test/parameters/echov5/client.gen.go | 3378 ----------------- .../parameters/echov5/echov5_param_test.go | 381 -- .../parameters/echov5/{ => gen}/server.gen.go | 4 +- .../parameters/echov5/{ => gen}/types.gen.go | 4 +- .../test/parameters/echov5/server.cfg.yaml | 4 +- internal/test/parameters/echov5/server.go | 59 +- .../test/parameters/echov5/types.cfg.yaml | 4 +- .../test/parameters/param_roundtrip_test.go | 10 + 9 files changed, 49 insertions(+), 3800 deletions(-) delete mode 100644 internal/test/parameters/echov5/client.cfg.yaml delete mode 100644 internal/test/parameters/echov5/client.gen.go delete mode 100644 internal/test/parameters/echov5/echov5_param_test.go rename internal/test/parameters/echov5/{ => gen}/server.gen.go (99%) rename internal/test/parameters/echov5/{ => gen}/types.gen.go (97%) diff --git a/internal/test/parameters/echov5/client.cfg.yaml b/internal/test/parameters/echov5/client.cfg.yaml deleted file mode 100644 index 79dabbe746..0000000000 --- a/internal/test/parameters/echov5/client.cfg.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# yaml-language-server: $schema=../../../../configuration-schema.json -package: echov5params -generate: - client: true -output: client.gen.go diff --git a/internal/test/parameters/echov5/client.gen.go b/internal/test/parameters/echov5/client.gen.go deleted file mode 100644 index a6b498d5ec..0000000000 --- a/internal/test/parameters/echov5/client.gen.go +++ /dev/null @@ -1,3378 +0,0 @@ -// Package echov5params 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 echov5params - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" - - "github.com/oapi-codegen/runtime" -) - -// 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 { - // GetContentObject request - GetContentObject(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetCookie request - GetCookie(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // EnumParams request - EnumParams(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetHeader request - GetHeader(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetLabelExplodeArray request - GetLabelExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) - - // 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) - - // GetSimpleExplodeArray request - GetSimpleExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) - - // 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) - - // GetSimpleNoExplodeObject request - GetSimpleNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetSimplePrimitive request - GetSimplePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetStartingWithNumber request - GetStartingWithNumber(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -func (c *Client) GetContentObject(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetContentObjectRequest(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) GetCookie(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetCookieRequest(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) EnumParams(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewEnumParamsRequest(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) GetHeader(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetHeaderRequest(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) GetLabelExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetLabelExplodeArrayRequest(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) GetLabelExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetLabelExplodeObjectRequest(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) 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 { - 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) GetLabelNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetLabelNoExplodeObjectRequest(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) 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 { - 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) GetMatrixExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetMatrixExplodeObjectRequest(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) 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 { - 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) GetMatrixNoExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetMatrixNoExplodeObjectRequest(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) 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 { - 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) GetDeepObject(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetDeepObjectRequest(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) 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 { - 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) GetSimpleExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetSimpleExplodeArrayRequest(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) GetSimpleExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetSimpleExplodeObjectRequest(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) 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 { - 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) GetSimpleNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetSimpleNoExplodeObjectRequest(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) GetSimplePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetSimplePrimitiveRequest(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) GetStartingWithNumber(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetStartingWithNumberRequest(c.Server, n1param) - 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) -} - -// NewGetContentObjectRequest generates requests for GetContentObject -func NewGetContentObjectRequest(server string, param ComplexObject) (*http.Request, error) { - var err error - - var pathParam0 string - - var pathParamBuf0 []byte - pathParamBuf0, err = json.Marshal(param) - if err != nil { - return nil, err - } - pathParam0 = string(pathParamBuf0) - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/contentObject/%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 -} - -// NewGetCookieRequest generates requests for GetCookie -func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/cookie") - 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.P != nil { - var cookieParam0 string - - cookieParam0, err = runtime.StyleParamWithOptions("simple", false, "p", *params.P, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"}) - if err != nil { - return nil, err - } - - cookie0 := &http.Cookie{ - Name: "p", - Value: cookieParam0, - } - req.AddCookie(cookie0) - } - - if params.Ep != nil { - var cookieParam1 string - - cookieParam1, err = runtime.StyleParamWithOptions("simple", true, "ep", *params.Ep, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"}) - if err != nil { - return nil, err - } - - cookie1 := &http.Cookie{ - Name: "ep", - Value: cookieParam1, - } - req.AddCookie(cookie1) - } - - if params.Ea != nil { - var cookieParam2 string - - cookieParam2, err = runtime.StyleParamWithOptions("simple", true, "ea", *params.Ea, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""}) - if err != nil { - return nil, err - } - - cookie2 := &http.Cookie{ - Name: "ea", - Value: cookieParam2, - } - req.AddCookie(cookie2) - } - - if params.A != nil { - var cookieParam3 string - - cookieParam3, err = runtime.StyleParamWithOptions("simple", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""}) - if err != nil { - return nil, err - } - - cookie3 := &http.Cookie{ - Name: "a", - Value: cookieParam3, - } - req.AddCookie(cookie3) - } - - if params.Eo != nil { - var cookieParam4 string - - cookieParam4, err = runtime.StyleParamWithOptions("simple", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""}) - if err != nil { - return nil, err - } - - cookie4 := &http.Cookie{ - Name: "eo", - Value: cookieParam4, - } - req.AddCookie(cookie4) - } - - if params.O != nil { - var cookieParam5 string - - cookieParam5, err = runtime.StyleParamWithOptions("simple", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""}) - if err != nil { - return nil, err - } - - cookie5 := &http.Cookie{ - Name: "o", - Value: cookieParam5, - } - req.AddCookie(cookie5) - } - - if params.Co != nil { - var cookieParam6 string - - var cookieParamBuf6 []byte - cookieParamBuf6, err = json.Marshal(*params.Co) - if err != nil { - return nil, err - } - cookieParam6 = url.QueryEscape(string(cookieParamBuf6)) - - cookie6 := &http.Cookie{ - Name: "co", - Value: cookieParam6, - } - req.AddCookie(cookie6) - } - - if params.N1s != nil { - var cookieParam7 string - - cookieParam7, err = runtime.StyleParamWithOptions("simple", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "string", Format: ""}) - if err != nil { - return nil, err - } - - cookie7 := &http.Cookie{ - Name: "1s", - Value: cookieParam7, - } - req.AddCookie(cookie7) - } - } - return req, nil -} - -// NewEnumParamsRequest generates requests for EnumParams -func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/enums") - 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.EnumPathParam != 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 _, 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 -} - -// NewGetHeaderRequest generates requests for GetHeader -func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/header") - 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.XPrimitive != nil { - var headerParam0 string - - 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 - } - - req.Header.Set("X-Primitive", headerParam0) - } - - if params.XPrimitiveExploded != nil { - var headerParam1 string - - 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 - } - - req.Header.Set("X-Primitive-Exploded", headerParam1) - } - - if params.XArrayExploded != nil { - var headerParam2 string - - 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 - } - - req.Header.Set("X-Array-Exploded", headerParam2) - } - - if params.XArray != nil { - var headerParam3 string - - headerParam3, err = runtime.StyleParamWithOptions("simple", false, "X-Array", *params.XArray, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "array", Format: ""}) - if err != nil { - return nil, err - } - - req.Header.Set("X-Array", headerParam3) - } - - if params.XObjectExploded != nil { - var headerParam4 string - - headerParam4, err = runtime.StyleParamWithOptions("simple", true, "X-Object-Exploded", *params.XObjectExploded, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""}) - if err != nil { - return nil, err - } - - req.Header.Set("X-Object-Exploded", headerParam4) - } - - if params.XObject != nil { - var headerParam5 string - - headerParam5, err = runtime.StyleParamWithOptions("simple", false, "X-Object", *params.XObject, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""}) - if err != nil { - return nil, err - } - - req.Header.Set("X-Object", headerParam5) - } - - if params.XComplexObject != nil { - var headerParam6 string - - var headerParamBuf6 []byte - headerParamBuf6, err = json.Marshal(*params.XComplexObject) - if err != nil { - return nil, err - } - headerParam6 = string(headerParamBuf6) - - req.Header.Set("X-Complex-Object", headerParam6) - } - - if params.N1StartingWithNumber != nil { - var headerParam7 string - - 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 - } - - req.Header.Set("1-Starting-With-Number", headerParam7) - } - - } - - return req, nil -} - -// NewGetLabelExplodeArrayRequest generates requests for GetLabelExplodeArray -func NewGetLabelExplodeArrayRequest(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: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/labelExplodeArray/%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 -} - -// NewGetLabelExplodeObjectRequest generates requests for GetLabelExplodeObject -func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("label", true, "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("/labelExplodeObject/%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 -} - -// 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 - } - - return req, nil -} - -// NewGetLabelNoExplodeArrayRequest generates requests for GetLabelNoExplodeArray -func NewGetLabelNoExplodeArrayRequest(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: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/labelNoExplodeArray/%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 -} - -// NewGetLabelNoExplodeObjectRequest generates requests for GetLabelNoExplodeObject -func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("label", 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("/labelNoExplodeObject/%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 -} - -// 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 - } - - return req, nil -} - -// NewGetMatrixExplodeArrayRequest generates requests for GetMatrixExplodeArray -func NewGetMatrixExplodeArrayRequest(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: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/matrixExplodeArray/%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 -} - -// NewGetMatrixExplodeObjectRequest generates requests for GetMatrixExplodeObject -func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("matrix", true, "id", id, 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("/matrixExplodeObject/%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 -} - -// 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 - } - - return req, nil -} - -// NewGetMatrixNoExplodeArrayRequest generates requests for GetMatrixNoExplodeArray -func NewGetMatrixNoExplodeArrayRequest(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: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/matrixNoExplodeArray/%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 -} - -// NewGetMatrixNoExplodeObjectRequest generates requests for GetMatrixNoExplodeObject -func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("matrix", false, "id", id, 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("/matrixNoExplodeObject/%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 -} - -// 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 - } - - return req, nil -} - -// NewGetPassThroughRequest generates requests for GetPassThrough -func NewGetPassThroughRequest(server string, param string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0 = param - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/passThrough/%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 -} - -// NewGetDeepObjectRequest generates requests for GetDeepObject -func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/queryDeepObject") - 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 queryFrag, err := runtime.StyleParamWithOptions("deepObject", true, "deepObj", params.DeepObj, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", 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 -} - -// 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) - } - } - - } - - 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 -} - -// NewGetQueryFormRequest generates requests for GetQueryForm -func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/queryForm") - 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.Ea != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.A != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.Eo != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.O != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.Ep != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.P != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.Ps != 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 _, qp := range strings.Split(queryFrag, "&") { - rawQueryFragments = append(rawQueryFragments, qp) - } - } - - } - - if params.Co != nil { - - if queryParamBuf, err := json.Marshal(*params.Co); err != nil { - return nil, err - } else { - queryValues.Add("co", string(queryParamBuf)) - } - - } - - if params.N1s != 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 _, 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 -} - -// NewGetSimpleExplodeArrayRequest generates requests for GetSimpleExplodeArray -func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/simpleExplodeArray/%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 -} - -// NewGetSimpleExplodeObjectRequest generates requests for GetSimpleExplodeObject -func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("simple", true, "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("/simpleExplodeObject/%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 -} - -// NewGetSimpleExplodePrimitiveRequest generates requests for GetSimpleExplodePrimitive -func NewGetSimpleExplodePrimitiveRequest(server string, param int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("simple", 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("/simpleExplodePrimitive/%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 -} - -// NewGetSimpleNoExplodeArrayRequest generates requests for GetSimpleNoExplodeArray -func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""}) - if err != nil { - return nil, err - } - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/simpleNoExplodeArray/%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 -} - -// 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.StyleParamWithOptions("simple", 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("/simplePrimitive/%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 -} - -// NewGetStartingWithNumberRequest generates requests for GetStartingWithNumber -func NewGetStartingWithNumberRequest(server string, n1param string) (*http.Request, error) { - var err error - - var pathParam0 string - - pathParam0 = n1param - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/startingWithNumber/%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 { - // GetContentObjectWithResponse request - GetContentObjectWithResponse(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*GetContentObjectResponse, error) - - // GetCookieWithResponse request - GetCookieWithResponse(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*GetCookieResponse, error) - - // EnumParamsWithResponse request - EnumParamsWithResponse(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*EnumParamsResponse, error) - - // GetHeaderWithResponse request - GetHeaderWithResponse(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*GetHeaderResponse, error) - - // GetLabelExplodeArrayWithResponse request - GetLabelExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelExplodeArrayResponse, error) - - // 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) - - // GetSimpleExplodeArrayWithResponse request - GetSimpleExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodeArrayResponse, error) - - // 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) - - // GetSimpleNoExplodeObjectWithResponse request - GetSimpleNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeObjectResponse, error) - - // GetSimplePrimitiveWithResponse request - GetSimplePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimplePrimitiveResponse, error) - - // GetStartingWithNumberWithResponse request - GetStartingWithNumberWithResponse(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*GetStartingWithNumberResponse, error) -} - -type GetContentObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetContentObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetContentObjectResponse) 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 GetContentObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetCookieResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetCookieResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetCookieResponse) 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 GetCookieResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type EnumParamsResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r EnumParamsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r EnumParamsResponse) 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 EnumParamsResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetHeaderResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetHeaderResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetHeaderResponse) 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 GetHeaderResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetLabelExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetLabelExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLabelExplodeArrayResponse) 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 GetLabelExplodeArrayResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetLabelExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetLabelExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLabelExplodeObjectResponse) 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 GetLabelExplodeObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetLabelExplodePrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// 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 -} - -// Status returns HTTPResponse.Status -func (r GetLabelNoExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLabelNoExplodeArrayResponse) 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 GetLabelNoExplodeArrayResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetLabelNoExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetLabelNoExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLabelNoExplodeObjectResponse) 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 GetLabelNoExplodeObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetLabelPrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetLabelPrimitiveResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLabelPrimitiveResponse) 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 GetLabelPrimitiveResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixExplodeArrayResponse) 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 GetMatrixExplodeArrayResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixExplodeObjectResponse) 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 GetMatrixExplodeObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixExplodePrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixExplodePrimitiveResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixExplodePrimitiveResponse) 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 GetMatrixExplodePrimitiveResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixNoExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixNoExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixNoExplodeArrayResponse) 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 GetMatrixNoExplodeArrayResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixNoExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixNoExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixNoExplodeObjectResponse) 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 GetMatrixNoExplodeObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetMatrixPrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetMatrixPrimitiveResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetMatrixPrimitiveResponse) 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 GetMatrixPrimitiveResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetPassThroughResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetPassThroughResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetPassThroughResponse) 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 GetPassThroughResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetDeepObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetDeepObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetDeepObjectResponse) 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 GetDeepObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetQueryDelimitedResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetQueryDelimitedResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetQueryDelimitedResponse) 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 GetQueryDelimitedResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetQueryFormResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetQueryFormResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetQueryFormResponse) 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 GetQueryFormResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetSimpleExplodeArrayResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetSimpleExplodeArrayResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetSimpleExplodeArrayResponse) 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 GetSimpleExplodeArrayResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetSimpleExplodeObjectResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// Status returns HTTPResponse.Status -func (r GetSimpleExplodeObjectResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetSimpleExplodeObjectResponse) 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 GetSimpleExplodeObjectResponse) ContentType() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Header.Get("Content-Type") - } - return "" -} - -type GetSimpleExplodePrimitiveResponse struct { - Body []byte - HTTPResponse *http.Response -} - -// 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 -} - -// 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 -} - -// 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 -} - -// 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 -} - -// 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) -} - -// GetCookieWithResponse request returning *GetCookieResponse -func (c *ClientWithResponses) GetCookieWithResponse(ctx context.Context, params *GetCookieParams, reqEditors ...RequestEditorFn) (*GetCookieResponse, error) { - rsp, err := c.GetCookie(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetCookieResponse(rsp) -} - -// EnumParamsWithResponse request returning *EnumParamsResponse -func (c *ClientWithResponses) EnumParamsWithResponse(ctx context.Context, params *EnumParamsParams, reqEditors ...RequestEditorFn) (*EnumParamsResponse, error) { - rsp, err := c.EnumParams(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseEnumParamsResponse(rsp) -} - -// GetHeaderWithResponse request returning *GetHeaderResponse -func (c *ClientWithResponses) GetHeaderWithResponse(ctx context.Context, params *GetHeaderParams, reqEditors ...RequestEditorFn) (*GetHeaderResponse, error) { - rsp, err := c.GetHeader(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetHeaderResponse(rsp) -} - -// GetLabelExplodeArrayWithResponse request returning *GetLabelExplodeArrayResponse -func (c *ClientWithResponses) GetLabelExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelExplodeArrayResponse, error) { - rsp, err := c.GetLabelExplodeArray(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetLabelExplodeArrayResponse(rsp) -} - -// GetLabelExplodeObjectWithResponse request returning *GetLabelExplodeObjectResponse -func (c *ClientWithResponses) GetLabelExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelExplodeObjectResponse, error) { - rsp, err := c.GetLabelExplodeObject(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetLabelNoExplodeArrayResponse(rsp) -} - -// GetLabelNoExplodeObjectWithResponse request returning *GetLabelNoExplodeObjectResponse -func (c *ClientWithResponses) GetLabelNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelNoExplodeObjectResponse, error) { - rsp, err := c.GetLabelNoExplodeObject(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetMatrixExplodeArrayResponse(rsp) -} - -// GetMatrixExplodeObjectWithResponse request returning *GetMatrixExplodeObjectResponse -func (c *ClientWithResponses) GetMatrixExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixExplodeObjectResponse, error) { - rsp, err := c.GetMatrixExplodeObject(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetMatrixNoExplodeArrayResponse(rsp) -} - -// GetMatrixNoExplodeObjectWithResponse request returning *GetMatrixNoExplodeObjectResponse -func (c *ClientWithResponses) GetMatrixNoExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixNoExplodeObjectResponse, error) { - rsp, err := c.GetMatrixNoExplodeObject(ctx, id, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetPassThroughResponse(rsp) -} - -// GetDeepObjectWithResponse request returning *GetDeepObjectResponse -func (c *ClientWithResponses) GetDeepObjectWithResponse(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*GetDeepObjectResponse, error) { - rsp, err := c.GetDeepObject(ctx, params, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetQueryFormResponse(rsp) -} - -// GetSimpleExplodeArrayWithResponse request returning *GetSimpleExplodeArrayResponse -func (c *ClientWithResponses) GetSimpleExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodeArrayResponse, error) { - rsp, err := c.GetSimpleExplodeArray(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetSimpleExplodeArrayResponse(rsp) -} - -// GetSimpleExplodeObjectWithResponse request returning *GetSimpleExplodeObjectResponse -func (c *ClientWithResponses) GetSimpleExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleExplodeObjectResponse, error) { - rsp, err := c.GetSimpleExplodeObject(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - 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...) - if err != nil { - return nil, err - } - return ParseGetSimpleNoExplodeArrayResponse(rsp) -} - -// GetSimpleNoExplodeObjectWithResponse request returning *GetSimpleNoExplodeObjectResponse -func (c *ClientWithResponses) GetSimpleNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeObjectResponse, error) { - rsp, err := c.GetSimpleNoExplodeObject(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetSimpleNoExplodeObjectResponse(rsp) -} - -// GetSimplePrimitiveWithResponse request returning *GetSimplePrimitiveResponse -func (c *ClientWithResponses) GetSimplePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimplePrimitiveResponse, error) { - rsp, err := c.GetSimplePrimitive(ctx, param, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetSimplePrimitiveResponse(rsp) -} - -// GetStartingWithNumberWithResponse request returning *GetStartingWithNumberResponse -func (c *ClientWithResponses) GetStartingWithNumberWithResponse(ctx context.Context, n1param string, reqEditors ...RequestEditorFn) (*GetStartingWithNumberResponse, error) { - rsp, err := c.GetStartingWithNumber(ctx, n1param, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetStartingWithNumberResponse(rsp) -} - -// ParseGetContentObjectResponse parses an HTTP response from a GetContentObjectWithResponse call -func ParseGetContentObjectResponse(rsp *http.Response) (*GetContentObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetContentObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetCookieResponse parses an HTTP response from a GetCookieWithResponse call -func ParseGetCookieResponse(rsp *http.Response) (*GetCookieResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetCookieResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseEnumParamsResponse parses an HTTP response from a EnumParamsWithResponse call -func ParseEnumParamsResponse(rsp *http.Response) (*EnumParamsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &EnumParamsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetHeaderResponse parses an HTTP response from a GetHeaderWithResponse call -func ParseGetHeaderResponse(rsp *http.Response) (*GetHeaderResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetHeaderResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetLabelExplodeArrayResponse parses an HTTP response from a GetLabelExplodeArrayWithResponse call -func ParseGetLabelExplodeArrayResponse(rsp *http.Response) (*GetLabelExplodeArrayResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetLabelExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetLabelExplodeObjectResponse parses an HTTP response from a GetLabelExplodeObjectWithResponse call -func ParseGetLabelExplodeObjectResponse(rsp *http.Response) (*GetLabelExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetLabelExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetLabelNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetLabelNoExplodeObjectResponse parses an HTTP response from a GetLabelNoExplodeObjectWithResponse call -func ParseGetLabelNoExplodeObjectResponse(rsp *http.Response) (*GetLabelNoExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetLabelNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetMatrixExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetMatrixExplodeObjectResponse parses an HTTP response from a GetMatrixExplodeObjectWithResponse call -func ParseGetMatrixExplodeObjectResponse(rsp *http.Response) (*GetMatrixExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetMatrixExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetMatrixNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetMatrixNoExplodeObjectResponse parses an HTTP response from a GetMatrixNoExplodeObjectWithResponse call -func ParseGetMatrixNoExplodeObjectResponse(rsp *http.Response) (*GetMatrixNoExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetMatrixNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetPassThroughResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetDeepObjectResponse parses an HTTP response from a GetDeepObjectWithResponse call -func ParseGetDeepObjectResponse(rsp *http.Response) (*GetDeepObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetDeepObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetQueryFormResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetSimpleExplodeArrayResponse parses an HTTP response from a GetSimpleExplodeArrayWithResponse call -func ParseGetSimpleExplodeArrayResponse(rsp *http.Response) (*GetSimpleExplodeArrayResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetSimpleExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetSimpleExplodeObjectResponse parses an HTTP response from a GetSimpleExplodeObjectWithResponse call -func ParseGetSimpleExplodeObjectResponse(rsp *http.Response) (*GetSimpleExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetSimpleExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - 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) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetSimpleNoExplodeArrayResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetSimpleNoExplodeObjectResponse parses an HTTP response from a GetSimpleNoExplodeObjectWithResponse call -func ParseGetSimpleNoExplodeObjectResponse(rsp *http.Response) (*GetSimpleNoExplodeObjectResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetSimpleNoExplodeObjectResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetSimplePrimitiveResponse parses an HTTP response from a GetSimplePrimitiveWithResponse call -func ParseGetSimplePrimitiveResponse(rsp *http.Response) (*GetSimplePrimitiveResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetSimplePrimitiveResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} - -// ParseGetStartingWithNumberResponse parses an HTTP response from a GetStartingWithNumberWithResponse call -func ParseGetStartingWithNumberResponse(rsp *http.Response) (*GetStartingWithNumberResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetStartingWithNumberResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - return response, nil -} diff --git a/internal/test/parameters/echov5/echov5_param_test.go b/internal/test/parameters/echov5/echov5_param_test.go deleted file mode 100644 index 12e5eb5206..0000000000 --- a/internal/test/parameters/echov5/echov5_param_test.go +++ /dev/null @@ -1,381 +0,0 @@ -package echov5params - -import ( - "encoding/json" - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v5" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestEchoV5ParameterRoundTrip(t *testing.T) { - var s Server - e := echo.New() - RegisterHandlers(e, &s) - testImpl(t, e) -} - -func testImpl(t *testing.T, handler http.Handler) { - t.Helper() - - 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 - - doRoundTrip := func(t *testing.T, req *http.Request, target interface{}) { - t.Helper() - 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") - } - } - - t.Run("path", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - t.Run("primitive", func(t *testing.T) { - req, err := 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 := 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 := 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 := 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 := NewGetSimpleNoExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got Object - doRoundTrip(t, req, &got) - assert.Equal(t, expectedObject, got) - }) - t.Run("object explode", func(t *testing.T) { - req, err := NewGetSimpleExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got 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 := 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 := 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 := 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 := 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 := NewGetLabelNoExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got Object - doRoundTrip(t, req, &got) - assert.Equal(t, expectedObject, got) - }) - t.Run("object explode", func(t *testing.T) { - req, err := NewGetLabelExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got 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 := 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 := 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 := 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 := 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 := NewGetMatrixNoExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got Object - doRoundTrip(t, req, &got) - assert.Equal(t, expectedObject, got) - }) - t.Run("object explode", func(t *testing.T) { - req, err := NewGetMatrixExplodeObjectRequest(server, expectedObject) - require.NoError(t, err) - var got 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 := NewGetContentObjectRequest(server, expectedComplexObject) - require.NoError(t, err) - var got ComplexObject - doRoundTrip(t, req, &got) - assert.Equal(t, expectedComplexObject, got) - }) - t.Run("passthrough string", func(t *testing.T) { - req, err := NewGetPassThroughRequest(server, "hello world") - require.NoError(t, err) - var got string - doRoundTrip(t, req, &got) - assert.Equal(t, "hello world", got) - }) - }) - }) - - t.Run("query", func(t *testing.T) { - t.Run("form", func(t *testing.T) { - expectedArray2 := []int32{6, 7, 8} - expectedObject2 := 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 := GetQueryFormParams{ - Ea: &expectedArray, A: &expectedArray2, - Eo: &expectedObject, O: &expectedObject2, - Ep: &expectedPrimitive, P: &expectedPrimitive2, - Ps: &expectedPrimitiveString, Co: &expectedComplexObject, N1s: &expectedN1s, - } - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got GetQueryFormParams - doRoundTrip(t, req, &got) - assert.EqualValues(t, params, got) - }) - t.Run("exploded array only", func(t *testing.T) { - params := GetQueryFormParams{Ea: &expectedArray} - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetQueryFormParams{A: &expectedArray} - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetQueryFormParams{Eo: &expectedObject} - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetQueryFormParams{O: &expectedObject} - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetQueryFormParams{Ps: &expectedPrimitiveString} - req, err := NewGetQueryFormRequest(server, ¶ms) - require.NoError(t, err) - var got GetQueryFormParams - doRoundTrip(t, req, &got) - require.NotNil(t, got.Ps) - assert.Equal(t, expectedPrimitiveString, *got.Ps) - }) - }) - t.Run("deepObject", func(t *testing.T) { - params := GetDeepObjectParams{DeepObj: expectedComplexObject} - req, err := NewGetDeepObjectRequest(server, ¶ms) - require.NoError(t, err) - var got GetDeepObjectParams - doRoundTrip(t, req, &got) - assert.Equal(t, expectedComplexObject, got.DeepObj) - }) - t.Run("spaceDelimited", func(t *testing.T) { - }) - t.Run("pipeDelimited", func(t *testing.T) { - }) - }) - - t.Run("header", func(t *testing.T) { - expectedArray2 := []int32{6, 7, 8} - expectedObject2 := 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 := GetHeaderParams{ - XPrimitive: &expectedPrimitive2, XPrimitiveExploded: &expectedPrimitive, - XArrayExploded: &expectedArray, XArray: &expectedArray2, - XObjectExploded: &expectedObject, XObject: &expectedObject2, - XComplexObject: &expectedComplexObject, N1StartingWithNumber: &expectedN1s, - } - req, err := NewGetHeaderRequest(server, ¶ms) - require.NoError(t, err) - var got GetHeaderParams - doRoundTrip(t, req, &got) - assert.EqualValues(t, params, got) - }) - t.Run("primitive only", func(t *testing.T) { - params := GetHeaderParams{XPrimitive: &expectedPrimitive} - req, err := NewGetHeaderRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetHeaderParams{XArray: &expectedArray} - req, err := NewGetHeaderRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetHeaderParams{XObject: &expectedObject} - req, err := NewGetHeaderRequest(server, ¶ms) - require.NoError(t, err) - var got GetHeaderParams - doRoundTrip(t, req, &got) - require.NotNil(t, got.XObject) - assert.Equal(t, expectedObject, *got.XObject) - }) - }) - - t.Run("cookie", func(t *testing.T) { - expectedArray2 := []int32{6, 7, 8} - expectedObject2 := 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 := GetCookieParams{ - P: &expectedPrimitive2, Ep: &expectedPrimitive, - Ea: &expectedArray, A: &expectedArray2, - Eo: &expectedObject, O: &expectedObject2, - Co: &expectedComplexObject, N1s: &expectedN1s, - } - req, err := NewGetCookieRequest(server, ¶ms) - require.NoError(t, err) - var got GetCookieParams - doRoundTrip(t, req, &got) - assert.EqualValues(t, params, got) - }) - t.Run("primitive only", func(t *testing.T) { - params := GetCookieParams{P: &expectedPrimitive} - req, err := NewGetCookieRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetCookieParams{A: &expectedArray} - req, err := NewGetCookieRequest(server, ¶ms) - require.NoError(t, err) - var got 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 := GetCookieParams{O: &expectedObject} - req, err := NewGetCookieRequest(server, ¶ms) - require.NoError(t, err) - var got GetCookieParams - doRoundTrip(t, req, &got) - require.NotNil(t, got.O) - assert.Equal(t, expectedObject, *got.O) - }) - }) -} diff --git a/internal/test/parameters/echov5/server.gen.go b/internal/test/parameters/echov5/gen/server.gen.go similarity index 99% rename from internal/test/parameters/echov5/server.gen.go rename to internal/test/parameters/echov5/gen/server.gen.go index fa9568f23f..30bebc6b46 100644 --- a/internal/test/parameters/echov5/server.gen.go +++ b/internal/test/parameters/echov5/gen/server.gen.go @@ -1,7 +1,7 @@ -// Package echov5params provides primitives to interact with the openapi HTTP API. +// 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 echov5params +package echov5paramsgen import ( "bytes" diff --git a/internal/test/parameters/echov5/types.gen.go b/internal/test/parameters/echov5/gen/types.gen.go similarity index 97% rename from internal/test/parameters/echov5/types.gen.go rename to internal/test/parameters/echov5/gen/types.gen.go index ec30efbad9..f9ac88c94a 100644 --- a/internal/test/parameters/echov5/types.gen.go +++ b/internal/test/parameters/echov5/gen/types.gen.go @@ -1,7 +1,7 @@ -// Package echov5params provides primitives to interact with the openapi HTTP API. +// 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 echov5params +package echov5paramsgen // Defines values for EnumParamsParamsEnumPathParam. const ( diff --git a/internal/test/parameters/echov5/server.cfg.yaml b/internal/test/parameters/echov5/server.cfg.yaml index 49ef08e89f..6df3ac93c1 100644 --- a/internal/test/parameters/echov5/server.cfg.yaml +++ b/internal/test/parameters/echov5/server.cfg.yaml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=../../../../configuration-schema.json -package: echov5params +package: echov5paramsgen generate: echo5-server: true embedded-spec: true -output: server.gen.go +output: gen/server.gen.go diff --git a/internal/test/parameters/echov5/server.go b/internal/test/parameters/echov5/server.go index 50e16af349..c14531f150 100644 --- a/internal/test/parameters/echov5/server.go +++ b/internal/test/parameters/echov5/server.go @@ -1,6 +1,5 @@ //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 -//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client.cfg.yaml ../parameters.yaml package echov5params @@ -8,34 +7,38 @@ import ( "net/http" "github.com/labstack/echo/v5" + + gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5/gen" ) type Server struct{} -func (s *Server) GetContentObject(ctx *echo.Context, param ComplexObject) error { return (*ctx).JSON(http.StatusOK, param) } -func (s *Server) GetCookie(ctx *echo.Context, params GetCookieParams) error { return (*ctx).JSON(http.StatusOK, params) } -func (s *Server) EnumParams(ctx *echo.Context, params EnumParamsParams) error { return (*ctx).NoContent(http.StatusNoContent) } -func (s *Server) GetHeader(ctx *echo.Context, params 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 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 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 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 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 GetDeepObjectParams) error { return (*ctx).JSON(http.StatusOK, params) } -func (s *Server) GetQueryDelimited(ctx *echo.Context, params GetQueryDelimitedParams) error { return (*ctx).JSON(http.StatusOK, params) } -func (s *Server) GetQueryForm(ctx *echo.Context, params 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 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 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) } +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 index 7cf80b491c..97fafeae65 100644 --- a/internal/test/parameters/echov5/types.cfg.yaml +++ b/internal/test/parameters/echov5/types.cfg.yaml @@ -1,5 +1,5 @@ # yaml-language-server: $schema=../../../../configuration-schema.json -package: echov5params +package: echov5paramsgen generate: models: true -output: types.gen.go +output: gen/types.gen.go diff --git a/internal/test/parameters/param_roundtrip_test.go b/internal/test/parameters/param_roundtrip_test.go index 2bca8801e3..6a64a99040 100644 --- a/internal/test/parameters/param_roundtrip_test.go +++ b/internal/test/parameters/param_roundtrip_test.go @@ -13,6 +13,7 @@ import ( "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" @@ -21,6 +22,8 @@ import ( 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" @@ -40,6 +43,13 @@ func TestEchoParameterRoundTrip(t *testing.T) { 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() From c5641fd52f0d95a95f2def767753b584b83977e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Tollk=C3=B6tter?= <155718143+rd-andreas-tollkoetter@users.noreply.github.com> Date: Tue, 19 May 2026 18:54:38 +0200 Subject: [PATCH 287/293] Add functions to response models for schema-extraction (#2379) * added Getter functions for response bodies * add configuration option to skip response body getter generation * Update config schema, regenerate everything - Add `skip-response-body-getters` to `configuration-schema.json` under `output-options` so schema-based config validation accepts the new flag (Greptile P1 on `configuration.go`). - Regenerate every committed `*.gen.go` fixture so the new default `GetBody()` and `Get()` response getters are reflected in the committed output (Greptile P1 on `client-with-responses.tmpl`). - Add `internal/test/outputoptions/response-body-getters/` covering both the default (`enabled/`) and opt-out (`skipped/`) code paths. The tests instantiate the generated response type and use reflection to assert the getters are present or absent as configured. --------- Co-authored-by: Marcin Romaszewicz --- configuration-schema.json | 4 + .../authenticated-api/echo/api/api.gen.go | 20 ++ .../authenticated-api/stdhttp/api/api.gen.go | 20 ++ examples/client/client.gen.go | 22 ++ examples/clienttypenameclash/client.gen.go | 10 + .../custom-client-type.gen.go | 10 + .../petstore-expanded/petstore-client.gen.go | 55 ++++ .../streaming/client/sse/streaming.gen.go | 5 + .../anonymous_inner_hoisting/client.gen.go | 56 ++++ .../test/any_of/codegen/inline/openapi.gen.go | 12 + .../any_of/codegen/ref_schema/openapi.gen.go | 10 + internal/test/any_of/param/param.gen.go | 5 + internal/test/client/client.gen.go | 40 +++ .../param-ref-sibling-omitempty/issue.gen.go | 5 + internal/test/issues/issue-1039/client.gen.go | 5 + internal/test/issues/issue-1087/api.gen.go | 30 ++ internal/test/issues/issue-1180/issue.gen.go | 5 + .../test/issues/issue-1182/pkg1/pkg1.gen.go | 5 + .../test/issues/issue-1189/issue1189.gen.go | 10 + .../issue-1208-1209/issue-multi-json.gen.go | 25 ++ .../test/issues/issue-1212/pkg1/pkg1.gen.go | 5 + .../issues/issue-1277/content-array.gen.go | 10 + .../test/issues/issue-1298/issue1298.gen.go | 5 + .../test/issues/issue-1397/issue1397.gen.go | 5 + .../issue-1529/strict-echo/issue1529.gen.go | 20 ++ .../issue-1529/strict-fiber/issue1529.gen.go | 20 ++ .../issue-1529/strict-iris/issue1529.gen.go | 20 ++ internal/test/issues/issue-1914/client.gen.go | 10 + .../issues/issue-2031/prefer/issue2031.gen.go | 5 + .../test/issues/issue-2190/issue2190.gen.go | 10 + .../test/issues/issue-2238/issue2238.gen.go | 5 + .../test/issues/issue-2329/issue2329.gen.go | 10 + internal/test/issues/issue-312/issue.gen.go | 25 ++ internal/test/issues/issue-52/issue.gen.go | 10 + .../issue-grab_import_names/issue.gen.go | 10 + .../issue-illegal_enum_names/issue.gen.go | 10 + .../test/issues/issue1799/client/out.gen.go | 35 +++ internal/test/issues/issue240/client.gen.go | 22 ++ .../name_conflict_resolution.gen.go | 178 +++++++++++ .../name_normalizer.gen.go | 10 + .../name_normalizer.gen.go | 10 + .../name_normalizer.gen.go | 10 + .../to-camel-case/name_normalizer.gen.go | 10 + .../unset/name_normalizer.gen.go | 10 + .../response-body-getters/enabled/config.yaml | 7 + .../response-body-getters/enabled/generate.go | 3 + .../enabled/response_body_getters.gen.go | 286 ++++++++++++++++++ .../enabled/response_body_getters_test.go | 50 +++ .../response-body-getters/skipped/config.yaml | 8 + .../response-body-getters/skipped/generate.go | 3 + .../skipped/response_body_getters.gen.go | 271 +++++++++++++++++ .../skipped/response_body_getters_test.go | 24 ++ .../response-body-getters/spec.yaml | 51 ++++ .../test/parameters/client/gen/client.gen.go | 135 +++++++++ internal/test/pathalias/client.gen.go | 20 ++ internal/test/schemas/schemas.gen.go | 103 +++++++ .../test/strict-server/client/client.gen.go | 110 +++++++ pkg/codegen/configuration.go | 3 + .../templates/client-with-responses.tmpl | 14 + 59 files changed, 1907 insertions(+) create mode 100644 internal/test/outputoptions/response-body-getters/enabled/config.yaml create mode 100644 internal/test/outputoptions/response-body-getters/enabled/generate.go create mode 100644 internal/test/outputoptions/response-body-getters/enabled/response_body_getters.gen.go create mode 100644 internal/test/outputoptions/response-body-getters/enabled/response_body_getters_test.go create mode 100644 internal/test/outputoptions/response-body-getters/skipped/config.yaml create mode 100644 internal/test/outputoptions/response-body-getters/skipped/generate.go create mode 100644 internal/test/outputoptions/response-body-getters/skipped/response_body_getters.gen.go create mode 100644 internal/test/outputoptions/response-body-getters/skipped/response_body_getters_test.go create mode 100644 internal/test/outputoptions/response-body-getters/spec.yaml diff --git a/configuration-schema.json b/configuration-schema.json index 8f902ca708..9290cc121a 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -257,6 +257,10 @@ "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.", diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index d9b8dffea2..e3c5d2591a 100644 --- a/examples/authenticated-api/echo/api/api.gen.go +++ b/examples/authenticated-api/echo/api/api.gen.go @@ -293,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 { @@ -323,6 +333,16 @@ type AddThingResponse struct { 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 { diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index 97f16b2ff2..979cd32020 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -294,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 { @@ -324,6 +334,16 @@ type AddThingResponse struct { 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 { diff --git a/examples/client/client.gen.go b/examples/client/client.gen.go index 786d8c0b10..430496de89 100644 --- a/examples/client/client.gen.go +++ b/examples/client/client.gen.go @@ -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 { @@ -264,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 { diff --git a/examples/clienttypenameclash/client.gen.go b/examples/clienttypenameclash/client.gen.go index 4ed74d1777..99ab3e36a2 100644 --- a/examples/clienttypenameclash/client.gen.go +++ b/examples/clienttypenameclash/client.gen.go @@ -187,6 +187,16 @@ type UpdateClientResp struct { 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 { diff --git a/examples/custom-client-type/custom-client-type.gen.go b/examples/custom-client-type/custom-client-type.gen.go index 27f63d8185..adbb290453 100644 --- a/examples/custom-client-type/custom-client-type.gen.go +++ b/examples/custom-client-type/custom-client-type.gen.go @@ -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 { diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go index 5b5d01d78b..0b77852791 100644 --- a/examples/petstore-expanded/petstore-client.gen.go +++ b/examples/petstore-expanded/petstore-client.gen.go @@ -445,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 { @@ -476,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 { @@ -506,6 +536,16 @@ type DeletePetResponse struct { 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 { @@ -537,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 { diff --git a/examples/streaming/client/sse/streaming.gen.go b/examples/streaming/client/sse/streaming.gen.go index d20b2063e3..31b195d7e2 100644 --- a/examples/streaming/client/sse/streaming.gen.go +++ b/examples/streaming/client/sse/streaming.gen.go @@ -180,6 +180,11 @@ type GetStreamResponse struct { 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 { diff --git a/internal/test/anonymous_inner_hoisting/client.gen.go b/internal/test/anonymous_inner_hoisting/client.gen.go index 74fe6907c2..f022093572 100644 --- a/internal/test/anonymous_inner_hoisting/client.gen.go +++ b/internal/test/anonymous_inner_hoisting/client.gen.go @@ -928,6 +928,11 @@ type PostBodyPropertyOneOfResponse struct { 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 { @@ -957,6 +962,11 @@ type PostBodyRootOneOfResponse struct { 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 { @@ -991,6 +1001,20 @@ type GetResponseDeepNestedResponse struct { } } +// 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 { @@ -1023,6 +1047,18 @@ type GetResponseItemsOneOfResponse struct { } } +// 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 { @@ -1053,6 +1089,16 @@ type GetResponseRootAnyOfResponse struct { 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 { @@ -1083,6 +1129,16 @@ type GetResponseRootOneOfResponse struct { 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 { diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index c9eeb406b3..e1bb5cfbd7 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -313,6 +313,18 @@ type GetPetsResponse struct { } } +// 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 { diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index f8dcee8ce4..c69077123e 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -316,6 +316,16 @@ type GetPetsResponse struct { 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 { diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go index 694d466b9d..69e50dd32e 100644 --- a/internal/test/any_of/param/param.gen.go +++ b/internal/test/any_of/param/param.gen.go @@ -380,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 { diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go index 7a26ea68a2..aa6d0a4c7d 100644 --- a/internal/test/client/client.gen.go +++ b/internal/test/client/client.gen.go @@ -611,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 { @@ -640,6 +645,11 @@ type GetBothResponse struct { 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 { @@ -669,6 +679,11 @@ type PostJsonResponse struct { 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 { @@ -698,6 +713,11 @@ type GetJsonResponse struct { 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 { @@ -727,6 +747,11 @@ type PostOtherResponse struct { 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 { @@ -756,6 +781,11 @@ type GetOtherResponse struct { 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 { @@ -785,6 +815,11 @@ type GetJsonWithTrailingSlashResponse struct { 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 { @@ -814,6 +849,11 @@ type PostVendorJsonResponse struct { 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 { diff --git a/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go b/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go index 1cc7a983d3..3ee44a323d 100644 --- a/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go +++ b/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go @@ -217,6 +217,11 @@ type ListThingsResponse struct { 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 { diff --git a/internal/test/issues/issue-1039/client.gen.go b/internal/test/issues/issue-1039/client.gen.go index 63ef866784..9e9696094e 100644 --- a/internal/test/issues/issue-1039/client.gen.go +++ b/internal/test/issues/issue-1039/client.gen.go @@ -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 { diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go index dcbcca53ea..527ceb2e45 100644 --- a/internal/test/issues/issue-1087/api.gen.go +++ b/internal/test/issues/issue-1087/api.gen.go @@ -209,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 { diff --git a/internal/test/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go index 4f11b798d5..11fe0948f7 100644 --- a/internal/test/issues/issue-1180/issue.gen.go +++ b/internal/test/issues/issue-1180/issue.gen.go @@ -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 { diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go index e548f06834..e02ca358c2 100644 --- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go @@ -188,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 { diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index 45bd54e759..0296cf0d90 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -400,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 { 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 cb42ffded3..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 @@ -208,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 { diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go index 34e300a96c..23d6c7db96 100644 --- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go +++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go @@ -190,6 +190,11 @@ type TestResponse struct { HTTPResponse *http.Response } +// GetBody returns the raw response body bytes (Body) +func (r TestResponse) GetBody() []byte { + return r.Body +} + // Status returns HTTPResponse.Status func (r TestResponse) Status() string { if r.HTTPResponse != nil { diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index 4e13565987..e2e7846119 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -275,6 +275,16 @@ type TestResponse struct { 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 { diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go index 3d79747d26..a3229d9c86 100644 --- a/internal/test/issues/issue-1298/issue1298.gen.go +++ b/internal/test/issues/issue-1298/issue1298.gen.go @@ -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 { diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index c4330e0475..4ff816ae40 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -265,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 { diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go index e85c0b1bf2..349d34a553 100644 --- a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go @@ -194,6 +194,26 @@ type TestResponse struct { 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 { diff --git a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go index 5a9b77e70a..81bb0fad22 100644 --- a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go @@ -194,6 +194,26 @@ type TestResponse struct { 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 { diff --git a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go index e630e0fe63..69478c9163 100644 --- a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go +++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go @@ -194,6 +194,26 @@ type TestResponse struct { 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 { diff --git a/internal/test/issues/issue-1914/client.gen.go b/internal/test/issues/issue-1914/client.gen.go index 7af86aac02..4417fe5a8d 100644 --- a/internal/test/issues/issue-1914/client.gen.go +++ b/internal/test/issues/issue-1914/client.gen.go @@ -297,6 +297,11 @@ type PostPetResponse struct { 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 { @@ -326,6 +331,11 @@ type PostPet1234Response struct { 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 { diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go index 936ac9f762..e37c69d6a1 100644 --- a/internal/test/issues/issue-2031/prefer/issue2031.gen.go +++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go @@ -214,6 +214,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 { diff --git a/internal/test/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go index db31e6c1c3..cddf869b5d 100644 --- a/internal/test/issues/issue-2190/issue2190.gen.go +++ b/internal/test/issues/issue-2190/issue2190.gen.go @@ -188,6 +188,16 @@ type GetTestResponse struct { 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 { diff --git a/internal/test/issues/issue-2238/issue2238.gen.go b/internal/test/issues/issue-2238/issue2238.gen.go index 16e923002c..11d329f7d4 100644 --- a/internal/test/issues/issue-2238/issue2238.gen.go +++ b/internal/test/issues/issue-2238/issue2238.gen.go @@ -220,6 +220,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 { diff --git a/internal/test/issues/issue-2329/issue2329.gen.go b/internal/test/issues/issue-2329/issue2329.gen.go index 06e9baa719..0248c2fd11 100644 --- a/internal/test/issues/issue-2329/issue2329.gen.go +++ b/internal/test/issues/issue-2329/issue2329.gen.go @@ -396,6 +396,11 @@ type ListThingsResponse struct { 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 { @@ -425,6 +430,11 @@ type CreateThingResponse struct { 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 { diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go index 71fa081088..25763f9374 100644 --- a/internal/test/issues/issue-312/issue.gen.go +++ b/internal/test/issues/issue-312/issue.gen.go @@ -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 { @@ -326,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 { diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go index 9fb77c6726..5e0a502a4c 100644 --- a/internal/test/issues/issue-52/issue.gen.go +++ b/internal/test/issues/issue-52/issue.gen.go @@ -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 { 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 480b01aca8..08e66b4fcb 100644 --- a/internal/test/issues/issue-grab_import_names/issue.gen.go +++ b/internal/test/issues/issue-grab_import_names/issue.gen.go @@ -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 { 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 e5f45d16b1..09859b13cd 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -234,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 { diff --git a/internal/test/issues/issue1799/client/out.gen.go b/internal/test/issues/issue1799/client/out.gen.go index 4e70c70ddb..3ad144a2c5 100644 --- a/internal/test/issues/issue1799/client/out.gen.go +++ b/internal/test/issues/issue1799/client/out.gen.go @@ -422,6 +422,21 @@ type GetGetMultibodyResponse struct { 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 { @@ -452,6 +467,16 @@ type GetObjectResponse struct { 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 { @@ -481,6 +506,11 @@ type PostPostMultibodyResponse struct { 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 { @@ -510,6 +540,11 @@ type PostPostObjectResponse struct { 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 { diff --git a/internal/test/issues/issue240/client.gen.go b/internal/test/issues/issue240/client.gen.go index 2ce39f4154..cf1055c485 100644 --- a/internal/test/issues/issue240/client.gen.go +++ b/internal/test/issues/issue240/client.gen.go @@ -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 { @@ -269,6 +279,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 { diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index b97ae67fa3..1408a086d7 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -1889,6 +1889,19 @@ type ListEntitiesResponse struct { } } +// 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 { @@ -1919,6 +1932,16 @@ type PostFooResponse struct { 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 { @@ -1949,6 +1972,16 @@ type ListItemsResponse2 struct { 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 { @@ -1979,6 +2012,16 @@ type CreateItemResponse2 struct { 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 { @@ -2009,6 +2052,16 @@ type CreateOrderResponse struct { 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 { @@ -2039,6 +2092,16 @@ type GetOutcomeResponse struct { 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 { @@ -2068,6 +2131,11 @@ type PostOutcomeResponse struct { 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 { @@ -2098,6 +2166,16 @@ type SendPayloadResponse struct { 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 { @@ -2128,6 +2206,16 @@ type CreatePetResponse struct { 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 { @@ -2158,6 +2246,16 @@ type QueryResponse2 struct { 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 { @@ -2188,6 +2286,16 @@ type GetQuxResponse struct { 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 { @@ -2217,6 +2325,11 @@ type PostQuxResponse struct { 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 { @@ -2247,6 +2360,16 @@ type GetRenamedSchemaResponse struct { 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 { @@ -2276,6 +2399,11 @@ type PostRenamedSchemaResponse struct { 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 { @@ -2309,6 +2437,31 @@ type PatchResourceResponse struct { 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 { @@ -2339,6 +2492,16 @@ type GetStatusResponse2 struct { 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 { @@ -2369,6 +2532,16 @@ type GetZapResponse struct { 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 { @@ -2398,6 +2571,11 @@ type PostZapResponse struct { 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 { 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 index 5e5d1f4d81..8796ba4b3a 100644 --- 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 @@ -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 { 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 ee65dae6ac..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 @@ -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 { 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 6d924715f5..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 @@ -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 { 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 e9913ca86c..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 @@ -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 { 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 b511d10eb3..cbdde2a4ef 100644 --- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go +++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go @@ -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 { 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/parameters/client/gen/client.gen.go b/internal/test/parameters/client/gen/client.gen.go index d92fda1dc7..0baa386b1f 100644 --- a/internal/test/parameters/client/gen/client.gen.go +++ b/internal/test/parameters/client/gen/client.gen.go @@ -2063,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 { @@ -2092,6 +2097,11 @@ type GetCookieResponse struct { 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 { @@ -2121,6 +2131,11 @@ type EnumParamsResponse struct { 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 { @@ -2150,6 +2165,11 @@ type GetHeaderResponse struct { 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 { @@ -2179,6 +2199,11 @@ type GetLabelExplodeArrayResponse struct { 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 { @@ -2208,6 +2233,11 @@ type GetLabelExplodeObjectResponse struct { 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 { @@ -2237,6 +2267,11 @@ type GetLabelExplodePrimitiveResponse struct { 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 { @@ -2266,6 +2301,11 @@ type GetLabelNoExplodeArrayResponse struct { 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 { @@ -2295,6 +2335,11 @@ type GetLabelNoExplodeObjectResponse struct { 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 { @@ -2324,6 +2369,11 @@ type GetLabelPrimitiveResponse struct { 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 GetLabelPrimitiveResponse) Status() string { if r.HTTPResponse != nil { @@ -2353,6 +2403,11 @@ type GetMatrixExplodeArrayResponse struct { 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 GetMatrixExplodeArrayResponse) Status() string { if r.HTTPResponse != nil { @@ -2382,6 +2437,11 @@ type GetMatrixExplodeObjectResponse struct { 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 GetMatrixExplodeObjectResponse) Status() string { if r.HTTPResponse != nil { @@ -2411,6 +2471,11 @@ type GetMatrixExplodePrimitiveResponse struct { 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 GetMatrixExplodePrimitiveResponse) Status() string { if r.HTTPResponse != nil { @@ -2440,6 +2505,11 @@ type GetMatrixNoExplodeArrayResponse struct { 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 GetMatrixNoExplodeArrayResponse) Status() string { if r.HTTPResponse != nil { @@ -2469,6 +2539,11 @@ type GetMatrixNoExplodeObjectResponse struct { 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 GetMatrixNoExplodeObjectResponse) Status() string { if r.HTTPResponse != nil { @@ -2498,6 +2573,11 @@ type GetMatrixPrimitiveResponse struct { 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 GetMatrixPrimitiveResponse) Status() string { if r.HTTPResponse != nil { @@ -2527,6 +2607,11 @@ type GetPassThroughResponse struct { 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 GetPassThroughResponse) Status() string { if r.HTTPResponse != nil { @@ -2556,6 +2641,11 @@ type GetDeepObjectResponse struct { 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 GetDeepObjectResponse) Status() string { if r.HTTPResponse != nil { @@ -2585,6 +2675,11 @@ type GetQueryDelimitedResponse struct { 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 GetQueryDelimitedResponse) Status() string { if r.HTTPResponse != nil { @@ -2614,6 +2709,11 @@ type GetQueryFormResponse struct { 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 GetQueryFormResponse) Status() string { if r.HTTPResponse != nil { @@ -2643,6 +2743,11 @@ type GetSimpleExplodeArrayResponse struct { 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 GetSimpleExplodeArrayResponse) Status() string { if r.HTTPResponse != nil { @@ -2672,6 +2777,11 @@ type GetSimpleExplodeObjectResponse struct { 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 GetSimpleExplodeObjectResponse) Status() string { if r.HTTPResponse != nil { @@ -2701,6 +2811,11 @@ type GetSimpleExplodePrimitiveResponse struct { 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 { @@ -2730,6 +2845,11 @@ type GetSimpleNoExplodeArrayResponse struct { 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 { @@ -2759,6 +2879,11 @@ type GetSimpleNoExplodeObjectResponse struct { 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 { @@ -2788,6 +2913,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 { @@ -2817,6 +2947,11 @@ type GetStartingWithNumberResponse struct { 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 { diff --git a/internal/test/pathalias/client.gen.go b/internal/test/pathalias/client.gen.go index 1339886349..bf291c3cee 100644 --- a/internal/test/pathalias/client.gen.go +++ b/internal/test/pathalias/client.gen.go @@ -227,6 +227,16 @@ type GetTestResponse struct { 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 { @@ -257,6 +267,16 @@ type GetTestAlias0Response struct { 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 { diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 9568743929..05562de26b 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -812,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 { @@ -843,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 { @@ -876,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 { @@ -905,6 +963,11 @@ type Issue185Response struct { 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 { @@ -934,6 +997,11 @@ type Issue209Response struct { 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 { @@ -963,6 +1031,11 @@ type Issue30Response struct { 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 { @@ -993,6 +1066,16 @@ type GetIssues375Response struct { 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 { @@ -1022,6 +1105,11 @@ type Issue41Response struct { 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 { @@ -1051,6 +1139,11 @@ type Issue9Response struct { 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 { @@ -1081,6 +1174,16 @@ type Issue975Response struct { 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 { diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index e9888963f1..a076eddef0 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -1304,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 { @@ -1333,6 +1343,11 @@ type MultipartExampleResponse struct { 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 { @@ -1362,6 +1377,11 @@ type MultipartRelatedExampleResponse struct { 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 { @@ -1392,6 +1412,16 @@ type MultipleRequestAndResponseTypesResponse struct { 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 { @@ -1421,6 +1451,11 @@ type NoContentHeadersResponse struct { 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 { @@ -1451,6 +1486,16 @@ type RequiredJSONBodyResponse struct { 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 { @@ -1480,6 +1525,11 @@ type RequiredTextBodyResponse struct { 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 { @@ -1509,6 +1559,11 @@ type ReservedGoKeywordParametersResponse struct { 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 { @@ -1539,6 +1594,16 @@ type ReusableResponsesResponse struct { 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 { @@ -1568,6 +1633,11 @@ type TextExampleResponse struct { 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 { @@ -1597,6 +1667,11 @@ type UnknownExampleResponse struct { 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 { @@ -1626,6 +1701,11 @@ type UnspecifiedContentTypeResponse struct { 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 { @@ -1655,6 +1735,11 @@ type URLEncodedExampleResponse struct { 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 { @@ -1685,6 +1770,16 @@ type HeadersExampleResponse struct { 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 { @@ -1716,6 +1811,21 @@ type UnionExampleResponse struct { 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 func (r UnionExampleResponse) Status() string { if r.HTTPResponse != nil { diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index f2cc4c0162..dbcb0a6874 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -351,6 +351,9 @@ 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"` diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index 68ad3d4355..b2c9546639 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -53,6 +53,20 @@ type {{genResponseTypeName $opid | ucFirst}} struct { {{- 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 { From d5e17e9eb858e6b9461eef9400f115f7fa29d75e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 13:01:37 +0000 Subject: [PATCH 288/293] fix(deps): update module github.com/getkin/kin-openapi to v0.139.0 (go.mod) --- examples/go.mod | 6 +++--- examples/go.sum | 12 ++++++------ go.mod | 6 +++--- go.sum | 12 ++++++------ internal/test/go.mod | 6 +++--- internal/test/go.sum | 12 ++++++------ 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 2132ce7510..52a3f3b34e 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.138.0 + github.com/getkin/kin-openapi v0.139.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 @@ -85,8 +85,8 @@ require ( 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/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.12 // 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/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/examples/go.sum b/examples/go.sum index b8ab3ad12e..c90785cebe 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -57,8 +57,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= -github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= +github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= 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= @@ -221,10 +221,10 @@ github.com/oapi-codegen/runtime v1.4.1 h1:9nwLoI+KrWxzbBcp0jO/R8uXqbik/HUyCvPeU6 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= -github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +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= diff --git a/go.mod b/go.mod index 8cc1220b39..1d0f8b8657 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.25.9 require ( - github.com/getkin/kin-openapi v0.138.0 + github.com/getkin/kin-openapi v0.139.0 github.com/speakeasy-api/openapi v1.23.0 github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v3 v3.0.4 @@ -21,8 +21,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.12 // indirect + github.com/oasdiff/yaml v0.1.0 // indirect + github.com/oasdiff/yaml3 v0.0.13 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect diff --git a/go.sum b/go.sum index dfdae7c835..9214a786b9 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= -github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= +github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= 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= @@ -58,10 +58,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= -github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 8c270dbbd4..320cae3887 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.138.0 + github.com/getkin/kin-openapi v0.139.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 @@ -74,8 +74,8 @@ require ( 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/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.12 // 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/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index 742c531bcf..bb167df997 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -55,8 +55,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= -github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= +github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= 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= @@ -195,10 +195,10 @@ github.com/oapi-codegen/runtime v1.4.1 h1:9nwLoI+KrWxzbBcp0jO/R8uXqbik/HUyCvPeU6 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.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= -github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +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= From 1e1b2a251bc24450a5766af9d648e6601436e5aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 18:52:12 +0000 Subject: [PATCH 289/293] chore(deps): update dessant/label-actions action to v5.0.3 (.github/workflows) --- .github/workflows/label-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml index d83815765f..0d3f63627f 100644 --- a/.github/workflows/label-actions.yml +++ b/.github/workflows/label-actions.yml @@ -18,6 +18,6 @@ jobs: reaction: runs-on: ubuntu-latest steps: - - uses: dessant/label-actions@809e0f9bc11ce08744e7ccac7cd10621d00aba2f # v5.0.2 + - uses: dessant/label-actions@65225c179d3b2502f6eda7b3d15101a3f412366b # v5.0.3 with: github-token: ${{ github.token }} From c32c9d9eb4f52724d2333cbe8f0d8ed89f02f1af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 07:50:16 -0700 Subject: [PATCH 290/293] fix(deps): update module github.com/getkin/kin-openapi to v0.140.0 (go.mod) (#2395) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- examples/go.mod | 5 +---- examples/go.sum | 12 ++---------- go.mod | 8 +------- go.sum | 18 ++---------------- internal/test/go.mod | 5 +---- internal/test/go.sum | 12 ++---------- 6 files changed, 9 insertions(+), 51 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 52a3f3b34e..909480902e 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../ require ( - github.com/getkin/kin-openapi v0.139.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 @@ -84,11 +84,9 @@ require ( 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/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/perimeterx/marshmallow v1.1.5 // 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 @@ -110,7 +108,6 @@ require ( 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/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect diff --git a/examples/go.sum b/examples/go.sum index c90785cebe..0468e46daf 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -57,8 +57,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= -github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= +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= @@ -80,8 +80,6 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= @@ -198,8 +196,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w 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= @@ -239,8 +235,6 @@ 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -310,8 +304,6 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/go.mod b/go.mod index 1d0f8b8657..c28ff81291 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/oapi-codegen/oapi-codegen/v2 go 1.25.9 require ( - github.com/getkin/kin-openapi v0.139.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 @@ -18,17 +18,11 @@ require ( 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/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.9.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.1.0 // indirect github.com/oasdiff/yaml3 v0.0.13 // indirect - github.com/perimeterx/marshmallow v1.1.5 // 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/ugorji/go/codec v1.2.11 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - github.com/woodsbury/decimal128 v1.4.0 // indirect golang.org/x/sync v0.20.0 // indirect ) diff --git a/go.sum b/go.sum index 9214a786b9..7637121b6a 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5ql 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.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= -github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= +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= @@ -22,8 +22,6 @@ github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTe 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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= 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= @@ -42,8 +40,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN 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/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.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= @@ -51,10 +47,6 @@ 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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/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/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= @@ -74,8 +66,6 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -94,12 +84,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P 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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= diff --git a/internal/test/go.mod b/internal/test/go.mod index 320cae3887..8d111ae94d 100644 --- a/internal/test/go.mod +++ b/internal/test/go.mod @@ -5,7 +5,7 @@ go 1.25.9 replace github.com/oapi-codegen/oapi-codegen/v2 => ../../ require ( - github.com/getkin/kin-openapi v0.139.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 @@ -73,11 +73,9 @@ require ( 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/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/perimeterx/marshmallow v1.1.5 // 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 @@ -98,7 +96,6 @@ require ( 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/woodsbury/decimal128 v1.4.0 // indirect github.com/yosssi/ace v0.0.5 // indirect go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect golang.org/x/arch v0.26.0 // indirect diff --git a/internal/test/go.sum b/internal/test/go.sum index bb167df997..e6cb669a55 100644 --- a/internal/test/go.sum +++ b/internal/test/go.sum @@ -55,8 +55,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S 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.139.0 h1:pBFXcZJFwz9J1X64jzxlOoNgFm+TF7kNrs9+HJVN6Ic= -github.com/getkin/kin-openapi v0.139.0/go.mod h1:NGxPfE4PwS/TRXEbyx2RrxDFPZvxcWw31Tw8XXjPZLs= +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= @@ -78,8 +78,6 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= @@ -182,8 +180,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w 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= @@ -213,8 +209,6 @@ 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -281,8 +275,6 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= -github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= From a63186ffe57364ae0a09eaa7511f92c647908351 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Fri, 5 Jun 2026 07:21:56 -0700 Subject: [PATCH 291/293] Improve string escaping and add tests (#2396) Tighten how server URL values are emitted in the server-urls template so that spec-supplied text is always serialized into a proper Go context: - Route server descriptions and URLs through stripNewLines when they are written into generated // comments, so a multi-line value stays on the comment line instead of spilling into following lines. - Emit server URL and variable-default values via toGoString (now backed by strconv.Quote) instead of hand-wrapping them in quotes, so quotes, backslashes, and newlines are escaped correctly. - Harden StringToGoString to use strconv.Quote; the previous version only escaped double quotes and mishandled backslashes. This also tidies up the content-type literals that already used it. - Extend stripNewLines to drop carriage returns as well as newlines. Add regression tests covering the server-urls rendering and the StringToGoString escaping, and confirm `make generate` produces no changes to committed output. Co-authored-by: Claude Opus 4.8 --- pkg/codegen/server_urls_test.go | 114 +++++++++++++++++++++++++ pkg/codegen/template_helpers.go | 4 +- pkg/codegen/templates/server-urls.tmpl | 10 +-- pkg/codegen/utils.go | 8 +- pkg/codegen/utils_test.go | 13 +++ 5 files changed, 140 insertions(+), 9 deletions(-) diff --git a/pkg/codegen/server_urls_test.go b/pkg/codegen/server_urls_test.go index 2105649bfb..1fbc7e4577 100644 --- a/pkg/codegen/server_urls_test.go +++ b/pkg/codegen/server_urls_test.go @@ -1,7 +1,11 @@ package codegen import ( + "go/ast" + "go/parser" + "go/token" "testing" + "text/template" "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/assert" @@ -57,6 +61,116 @@ func TestUsedAndUndeclaredVariables(t *testing.T) { 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{ diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 1b46105323..a72d2911ce 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -322,8 +322,10 @@ 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) } diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl index ccb1786e73..b0cf2a86a5 100644 --- a/pkg/codegen/templates/server-urls.tmpl +++ b/pkg/codegen/templates/server-urls.tmpl @@ -3,8 +3,8 @@ {{ $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 }}{{ .OAPISchema.Description }}{{ else }}{{ .OAPISchema.URL }}{{ end }} -const {{ .GoName}} = "{{ .OAPISchema.URL }}" +// {{ .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 */}} @@ -36,7 +36,7 @@ const {{ .GoName}} = "{{ .OAPISchema.URL }}" type {{ $prefix }} string {{ if $v.Default }} // {{ $prefix }}Default is the default value for the `{{ $k }}` variable for {{ $goName }} - const {{ $prefix }}Default = "{{ $v.Default }}" + const {{ $prefix }}Default = {{ $v.Default | toGoString }} {{ end }} {{ end }} {{ end }} @@ -55,7 +55,7 @@ const {{ .GoName}} = "{{ .OAPISchema.URL }}" {{ end }} -// New{{ .GoName }} constructs the Server URL for {{ .OAPISchema.Description }}, with the provided variables. +// 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 -}} @@ -64,7 +64,7 @@ func New{{ .GoName }}({{ .NewServerFunctionParams }}) (string, error) { } {{ end -}} {{ end }} - u := "{{ .OAPISchema.URL }}" + u := {{ .OAPISchema.URL | toGoString }} {{ range $k, $v := $usedVars }} {{- $placeholder := printf "{%s}" $k -}} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index bc1763ed5b..496faf5648 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -905,10 +905,12 @@ func PathToTypeName(path []string) string { } // 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\""` +// 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 { - esc := strings.ReplaceAll(in, "\"", "\\\"") - return fmt.Sprintf("\"%s\"", esc) + return strconv.Quote(in) } // StringToGoComment renders a possible multi-line string as a valid Go-Comment. diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 9afe8b2d2e..df37c6d77a 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -544,6 +544,19 @@ func TestStringToGoStringValue(t *testing.T) { 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) { From bfe9fa3aa2b1ecfaea23d2960f48e02c596c433c Mon Sep 17 00:00:00 2001 From: Jamie Tanna Date: Sat, 6 Jun 2026 08:53:51 +0100 Subject: [PATCH 292/293] test: use Petstore spec from GitHub We're seeing intermittent issues from the Petstore project such as: error loading swagger spec in spec.yaml : failed to load OpenAPI specification: error resolving reference "https://petstore3.swagger.io/api/v3/openapi.json#/components/schemas/Pet": error loading "https://petstore3.swagger.io/api/v3/openapi.json": request returned status code 403 We can try and switch to the raw spec in GitHub to do this lookup, to avoid hitting the Petstore API. It's unclear if GitHub are going to be more performant, but it may help. --- .../test/externalref/externalref.cfg.yaml | 2 +- internal/test/externalref/externalref.gen.go | 19 ++++++++++--------- internal/test/externalref/spec.yaml | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/internal/test/externalref/externalref.cfg.yaml b/internal/test/externalref/externalref.cfg.yaml index dd7a93d019..56ecbbc41c 100644 --- a/internal/test/externalref/externalref.cfg.yaml +++ b/internal/test/externalref/externalref.cfg.yaml @@ -6,7 +6,7 @@ generate: import-mapping: ./packageA/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA ./packageB/spec.yaml: package_b github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB - https://petstore3.swagger.io/api/v3/openapi.json: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore + 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 82f42dfbbd..808391ca48 100644 --- a/internal/test/externalref/externalref.gen.go +++ b/internal/test/externalref/externalref.gen.go @@ -31,14 +31,15 @@ type Container struct { // 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{ - "pFRNb9swDP0rAbej0GTosINvbXdfDtupKAxGZhxttqRJTNag0H8fKDWNE6dIsl0Mmh8P7z3SfgHteu8s", - "WY5QvUDUK+oxhw/OMhpLQV58cJ4CG8olt/hJmmuU+GOgJVTwYboHmr6iTD3qX9jSXR096fpbnrqDpHYA", - "iwsB7ocA9wMAfQ7grS8p8MTn2tGbenNbO09WwjkxpJQUHOUfkKl1YTt2xjTypGfsfUdQfVKwdKFHhgqM", - "5S+fQQFvPZVXaikIMYs9HYzBV9fGfWvkYGwLQuQ1U2SBgue+k8mCAHrH6wTneVF/SFcPhFzhy5v+pEaK", - "Z/8ouXFta2gsWoFfOXY/QlcMZupzcNh27MRuZmgahoDbfeefgN5TAxWHNUlbZOR1xm4o6mA8G2cFi3hS", - "ahNjJ7yiSWQXhCrZdQ/VI+AGTYeLTnKebFMYRdc18HRCEGN7qOUK679jgbhEUlIQ6PfaBEk9FmuGdj6d", - "uyef7390SsLhncu/YvXXHjdj6Rp++tg0RraE3XxARtQfo8kdnfwbjYS8w++/f1ppT+GodCmFlDGMXbpc", - "NJw/HFCwoRDLrWaeZU1Qwe3N7GYmK0deCXBKfwMAAP//", + "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//", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, @@ -90,7 +91,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { } res[rawPath] = rawFunc } - for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "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 } 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 From 3a4debfeb0fe9938d5eaf86a5de62291d90ba24c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 07:49:18 +0000 Subject: [PATCH 293/293] docs(deps): update module github.com/oapi-codegen/oapi-codegen/v2 to v2.7.1 (readme.md) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb1c9a4ba4..c8d3d770ef 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ 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/oapi-codegen/oapi-codegen/v2.7.0/configuration-schema.json +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.7.1/configuration-schema.json package: api # ... ```