Repository: deepmap/oapi-codegen
Pull request #842 (2022-11-07 14:42:20)

Reverse the order of the middleware when they applied in gorilla/mux implementation
resolve https://github.com/deepmap/oapi-codegen/issues/841

jamietanna: Thanks for this - looks like this was because I copy-pasta'd Chi's server, and was resolved there in #787 

Patch:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..6757ff9
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,20 @@
+name: Lint project
+on: [push, pull_request]
+jobs:
+  build:
+    name: Build
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check out source code
+        uses: actions/checkout@v3
+
+      - name: Set up Go
+        uses: actions/setup-go@v3
+        with:
+          go-version-file: 'go.mod'
+
+      - name: golangci-lint
+        uses: golangci/golangci-lint-action@v3
+        with:
+          # Make sure this matches the version we've got in our `Makefile`
+          version: v1.50.1
diff --git a/.gitignore b/.gitignore
index f0b76c0..74762c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .idea
 .DS_Store
-.vscode/
\ No newline at end of file
+.vscode/
+bin/
diff --git a/Makefile b/Makefile
index 146075b..f767556 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,6 @@
+GOBASE=$(shell pwd)
+GOBIN=$(GOBASE)/bin
+
 help:
 	@echo "This is a helper makefile for oapi-codegen"
 	@echo "Targets:"
@@ -6,6 +9,15 @@ help:
 	@echo "    gin_example  generate gin example server code"
 	@echo "    tidy         tidy go mod"
 
+$(GOBIN)/golangci-lint:
+	curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.50.1
+
+.PHONY: tools
+tools: $(GOBIN)/golangci-lint
+
+lint: tools
+	$(GOBIN)/golangci-lint run ./...
+
 generate:
 	go generate ./...
 
diff --git a/README.md b/README.md
index 295edf3..c916753 100644
--- a/README.md
+++ b/README.md
@@ -632,6 +632,35 @@ which help you to use the various OpenAPI 3 Authentication mechanism.
   }
   ```
 
+- `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`)
+
+    ```yaml
+    components:
+      schemas:
+        Object:
+          properties:
+            category:
+              type: integer
+              enum: [0, 1, 2]
+              x-enum-varnames:
+                - notice
+                - warning
+                - urgent
+    ```
+
+    After code generation you will get this result:
+
+    ```go
+    // Defines values for ObjectCategory.
+    const (
+    	Notice  ObjectCategory = 0
+    	Urgent  ObjectCategory = 2
+    	Warning ObjectCategory = 1
+    )
+
+    // ObjectCategory defines model for Object.Category.
+    type ObjectCategory int
+    ```
 
 ## Using `oapi-codegen`
 
diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go
index 957b90f..aa33a76 100644
--- a/cmd/oapi-codegen/oapi-codegen.go
+++ b/cmd/oapi-codegen/oapi-codegen.go
@@ -17,7 +17,9 @@ import (
 	"flag"
 	"fmt"
 	"os"
+	"os/exec"
 	"path"
+	"path/filepath"
 	"runtime/debug"
 	"strings"
 
@@ -238,6 +240,10 @@ func main() {
 	// fields.
 	opts.Configuration = opts.UpdateDefaults()
 
+	if err := detectPackageName(&opts); err != nil {
+		errExit("%s\n", err)
+	}
+
 	// Now, ensure that the config options are valid.
 	if err := opts.Validate(); err != nil {
 		errExit("configuration error: %v\n", err)
@@ -309,6 +315,42 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
 	return templates, nil
 }
 
+// detectPackageName detects and sets PackageName if not already set.
+func detectPackageName(cfg *configuration) error {
+	if cfg.PackageName != "" {
+		return nil
+	}
+
+	if cfg.OutputFile != "" {
+		// Determine from the package name of the output file.
+		dir := filepath.Dir(cfg.PackageName)
+		cmd := exec.Command("go", "list", "-f", "{{.Name}}", dir)
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			outStr := string(out)
+			switch {
+			case strings.Contains(outStr, "expected 'package', found 'EOF'"):
+				// Redirecting the output to current directory which hasn't
+				// written anything yet, ignore.
+			case strings.HasPrefix(outStr, "no Go files in"):
+				// No go files yet, ignore.
+			default:
+				// Unexpected failure report.
+				return fmt.Errorf("detect package name for %q output: %q: %w", dir, string(out), err)
+			}
+		} else {
+			cfg.PackageName = string(out)
+			return nil
+		}
+	}
+
+	// Fallback to determining from the spec file name.
+	parts := strings.Split(filepath.Base(flag.Arg(0)), ".")
+	cfg.PackageName = codegen.LowercaseFirstCharacter(codegen.ToCamelCase(parts[0]))
+
+	return nil
+}
+
 // updateConfigFromFlags updates a loaded configuration from flags. Flags
 // override anything in the file. We generate errors for command line options
 // associated with the old style configuration
diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go
index 8dabdd9..abe997f 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -134,15 +134,13 @@ type GinServerOptions struct {
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
-	return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+	RegisterHandlersWithOptions(router, si, GinServerOptions{})
 }
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-
+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()})
@@ -156,14 +154,9 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
 	}
 
 	router.GET(options.BaseURL+"/pets", wrapper.FindPets)
-
 	router.POST(options.BaseURL+"/pets", wrapper.AddPet)
-
 	router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet)
-
 	router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
-
-	return router
 }
 
 // Base64 encoded, gzipped, json marshaled Swagger object
diff --git a/examples/petstore-expanded/gin/petstore.go b/examples/petstore-expanded/gin/petstore.go
index 2eae15b..a5b40a2 100644
--- a/examples/petstore-expanded/gin/petstore.go
+++ b/examples/petstore-expanded/gin/petstore.go
@@ -11,9 +11,10 @@ import (
 	"net/http"
 	"os"
 
+	"github.com/gin-gonic/gin"
+
 	"github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api"
 	middleware "github.com/deepmap/oapi-codegen/pkg/gin-middleware"
-	"github.com/gin-gonic/gin"
 )
 
 func NewGinPetServer(petStore *api.PetStore, port int) *http.Server {
@@ -35,7 +36,7 @@ func NewGinPetServer(petStore *api.PetStore, port int) *http.Server {
 	r.Use(middleware.OapiRequestValidator(swagger))
 
 	// We now register our petStore above as the handler for the interface
-	r = api.RegisterHandlers(r, petStore)
+	api.RegisterHandlers(r, petStore)
 
 	s := &http.Server{
 		Handler: r,
diff --git a/examples/petstore-expanded/gorilla/api/cfg.yaml b/examples/petstore-expanded/gorilla/api/cfg.yaml
index 7f1a2d7..8ead7a6 100644
--- a/examples/petstore-expanded/gorilla/api/cfg.yaml
+++ b/examples/petstore-expanded/gorilla/api/cfg.yaml
@@ -4,3 +4,5 @@ generate:
   models: true
   embedded-spec: true
 output: petstore.gen.go
+compatibility:
+  apply-gorilla-middleware-first-to-last: true
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index deac982..b55ecd0 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -114,8 +114,8 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 		siw.Handler.FindPets(w, r, params)
 	}
 
-	for _, middleware := range siw.HandlerMiddlewares {
-		handler = middleware(handler)
+	for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+		handler = siw.HandlerMiddlewares[i](handler)
 	}
 
 	handler(w, r.WithContext(ctx))
@@ -129,8 +129,8 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
 		siw.Handler.AddPet(w, r)
 	}
 
-	for _, middleware := range siw.HandlerMiddlewares {
-		handler = middleware(handler)
+	for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+		handler = siw.HandlerMiddlewares[i](handler)
 	}
 
 	handler(w, r.WithContext(ctx))
@@ -155,8 +155,8 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
 		siw.Handler.DeletePet(w, r, id)
 	}
 
-	for _, middleware := range siw.HandlerMiddlewares {
-		handler = middleware(handler)
+	for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+		handler = siw.HandlerMiddlewares[i](handler)
 	}
 
 	handler(w, r.WithContext(ctx))
@@ -181,8 +181,8 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
 		siw.Handler.FindPetByID(w, r, id)
 	}
 
-	for _, middleware := range siw.HandlerMiddlewares {
-		handler = middleware(handler)
+	for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+		handler = siw.HandlerMiddlewares[i](handler)
 	}
 
 	handler(w, r.WithContext(ctx))
diff --git a/go.mod b/go.mod
index 9dcd51f..528232e 100644
--- a/go.mod
+++ b/go.mod
@@ -4,15 +4,16 @@ require (
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0
 	github.com/getkin/kin-openapi v0.107.0
 	github.com/gin-gonic/gin v1.8.1
-	github.com/go-chi/chi/v5 v5.0.7
+	github.com/go-chi/chi/v5 v5.0.8
 	github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/mux v1.8.0
 	github.com/labstack/echo/v4 v4.9.1
 	github.com/lestrrat-go/jwx v1.2.25
-	github.com/matryer/moq v0.2.7
+	github.com/matryer/moq v0.3.0
 	github.com/stretchr/testify v1.8.1
-	golang.org/x/tools v0.2.0
+	golang.org/x/text v0.5.0
+	golang.org/x/tools v0.4.0
 	gopkg.in/yaml.v2 v2.4.0
 )
 
@@ -51,10 +52,9 @@ require (
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/fasttemplate v1.2.2 // indirect
 	golang.org/x/crypto v0.1.0 // indirect
-	golang.org/x/mod v0.6.0 // indirect
-	golang.org/x/net v0.1.0 // indirect
-	golang.org/x/sys v0.1.0 // indirect
-	golang.org/x/text v0.4.0 // indirect
+	golang.org/x/mod v0.7.0 // indirect
+	golang.org/x/net v0.3.0 // indirect
+	golang.org/x/sys v0.3.0 // indirect
 	golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
 	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
diff --git a/go.sum b/go.sum
index c8c1e6b..0f88eb0 100644
--- a/go.sum
+++ b/go.sum
@@ -16,8 +16,8 @@ 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.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
 github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
-github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
-github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
+github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
 github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
@@ -84,8 +84,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w=
-github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
+github.com/matryer/moq v0.3.0 h1:4j0goF/XK3pMTc7fJB3fveuTJoQNdavRX/78vlK3Xb4=
+github.com/matryer/moq v0.3.0/go.mod h1:RJ75ZZZD71hejp39j4crZLsEDszGk6iH4v4YsWFKH4s=
 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=
@@ -131,54 +131,37 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
 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/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
 golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
-golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-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/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 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-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-20210806184541-e5e7981a1069/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 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.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.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
 golang.org/x/time v0.0.0-20220411224347-583f2d630306/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.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
-golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
-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/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go
index 8c37a79..c09c2f1 100644
--- a/pkg/chi-middleware/oapi_validate.go
+++ b/pkg/chi-middleware/oapi_validate.go
@@ -7,6 +7,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"log"
 	"net/http"
 	"strings"
 
@@ -27,6 +28,8 @@ type Options struct {
 	Options           openapi3filter.Options
 	ErrorHandler      ErrorHandler
 	MultiErrorHandler MultiErrorHandler
+	// SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+	SilenceServersWarning bool
 }
 
 // OapiRequestValidator Creates middleware to validate request by swagger spec.
@@ -38,6 +41,10 @@ func OapiRequestValidator(swagger *openapi3.T) func(next http.Handler) http.Hand
 // OapiRequestValidatorWithOptions Creates middleware to validate request by swagger spec.
 // This middleware is good for net/http either since go-chi is 100% compatible with net/http.
 func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) func(next http.Handler) http.Handler {
+	if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+		log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+	}
+
 	router, err := gorillamux.NewRouter(swagger)
 	if err != nil {
 		panic(err)
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index 5086691..062dc95 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -396,7 +396,12 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op
 		return "", fmt.Errorf("error generating union boilerplate: %w", err)
 	}
 
-	typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate}, "")
+	unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, allTypes)
+	if err != nil {
+		return "", fmt.Errorf("error generating boilerplate for union types with additionalProperties: %w", err)
+	}
+
+	typeDefinitions := strings.Join([]string{enumsOut, typesOut, operationsOut, allOfBoilerplate, unionBoilerplate, unionAndAdditionalBoilerplate}, "")
 	return typeDefinitions, nil
 }
 
@@ -778,6 +783,26 @@ func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) (
 	return GenerateTemplates([]string{"union.tmpl"}, t, context)
 }
 
+func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) {
+	var filteredTypes []TypeDefinition
+	for _, t := range typeDefs {
+		if len(t.Schema.UnionElements) != 0 && t.Schema.HasAdditionalProperties {
+			filteredTypes = append(filteredTypes, t)
+		}
+	}
+
+	if len(filteredTypes) == 0 {
+		return "", nil
+	}
+	context := struct {
+		Types []TypeDefinition
+	}{
+		Types: filteredTypes,
+	}
+
+	return GenerateTemplates([]string{"union-and-additional-properties.tmpl"}, t, context)
+}
+
 // SanitizeCode runs sanitizers across the generated Go code to ensure the
 // generated code will be able to compile.
 func SanitizeCode(goCode string) string {
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index 1400c3c..afa4fc5 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -69,6 +69,11 @@ type CompatibilityOptions struct {
 	// 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
 	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
+	ApplyGorillaMiddlewareFirstToLast bool `yaml:"apply-gorilla-middleware-first-to-last,omitempty"`
 }
 
 // OutputOptions are used to modify the output code in some way.
diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go
index 69c4621..ad91ad0 100644
--- a/pkg/codegen/extension.go
+++ b/pkg/codegen/extension.go
@@ -17,6 +17,8 @@ const (
 	extPropGoJsonIgnore = "x-go-json-ignore"
 	extPropOmitEmpty    = "x-omitempty"
 	extPropExtraTags    = "x-oapi-codegen-extra-tags"
+	extEnumVarNames     = "x-enum-varnames"
+	extEnumNames        = "x-enumNames"
 )
 
 func extString(extPropValue interface{}) (string, error) {
@@ -78,3 +80,15 @@ func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) {
 
 	return goJsonIgnore, nil
 }
+
+func extParseEnumVarNames(extPropValue interface{}) ([]string, error) {
+	raw, ok := extPropValue.(json.RawMessage)
+	if !ok {
+		return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
+	}
+	var names []string
+	if err := json.Unmarshal(raw, &names); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal json: %w", err)
+	}
+	return names, nil
+}
diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go
index 610f0d2..466e55c 100644
--- a/pkg/codegen/merge_schemas.go
+++ b/pkg/codegen/merge_schemas.go
@@ -37,7 +37,7 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
 		if err != nil {
 			return Schema{}, err
 		}
-		schema, err = mergeOpenapiSchemas(schema, oneOfSchema)
+		schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true)
 		if err != nil {
 			return Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
 		}
@@ -74,7 +74,7 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) {
 	var schema openapi3.Schema
 	for _, schemaRef := range allOf {
 		var err error
-		schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value)
+		schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true)
 		if err != nil {
 			return openapi3.Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
 		}
@@ -84,7 +84,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) (openapi3.Schema, error) {
+func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) {
 	var result openapi3.Schema
 	if s1.Extensions != nil || s2.Extensions != nil {
 		result.Extensions = make(map[string]interface{})
@@ -219,8 +219,8 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema) (openapi3.Schema, error) {
 		result.AdditionalProperties = s2.AdditionalProperties
 	}
 
-	// Unhandled for now
-	if s1.Discriminator != nil || s2.Discriminator != nil {
+	// Allow discriminators for allOf merges, but disallow for one/anyOfs.
+	if !allOf && (s1.Discriminator != nil || s2.Discriminator != nil) {
 		return openapi3.Schema{}, errors.New("merging two schemas with discriminators is not supported")
 	}
 
diff --git a/pkg/codegen/prune.go b/pkg/codegen/prune.go
index b9f05f5..03df80f 100644
--- a/pkg/codegen/prune.go
+++ b/pkg/codegen/prune.go
@@ -28,14 +28,14 @@ func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error
 
 	for _, p := range swagger.Paths {
 		for _, param := range p.Parameters {
-			walkParameterRef(param, doFn)
+			_ = walkParameterRef(param, doFn)
 		}
 		for _, op := range p.Operations() {
-			walkOperation(op, doFn)
+			_ = walkOperation(op, doFn)
 		}
 	}
 
-	walkComponents(&swagger.Components, doFn)
+	_ = walkComponents(&swagger.Components, doFn)
 
 	return nil
 }
@@ -53,11 +53,11 @@ func walkOperation(op *openapi3.Operation, doFn func(RefWrapper) (bool, error))
 	_ = walkRequestBodyRef(op.RequestBody, doFn)
 
 	for _, response := range op.Responses {
-		walkResponseRef(response, doFn)
+		_ = walkResponseRef(response, doFn)
 	}
 
 	for _, callback := range op.Callbacks {
-		walkCallbackRef(callback, doFn)
+		_ = walkCallbackRef(callback, doFn)
 	}
 
 	return nil
@@ -126,25 +126,25 @@ func walkSchemaRef(ref *openapi3.SchemaRef, doFn func(RefWrapper) (bool, error))
 	}
 
 	for _, ref := range ref.Value.OneOf {
-		walkSchemaRef(ref, doFn)
+		_ = walkSchemaRef(ref, doFn)
 	}
 
 	for _, ref := range ref.Value.AnyOf {
-		walkSchemaRef(ref, doFn)
+		_ = walkSchemaRef(ref, doFn)
 	}
 
 	for _, ref := range ref.Value.AllOf {
-		walkSchemaRef(ref, doFn)
+		_ = walkSchemaRef(ref, doFn)
 	}
 
-	walkSchemaRef(ref.Value.Not, doFn)
-	walkSchemaRef(ref.Value.Items, doFn)
+	_ = walkSchemaRef(ref.Value.Not, doFn)
+	_ = walkSchemaRef(ref.Value.Items, doFn)
 
 	for _, ref := range ref.Value.Properties {
-		walkSchemaRef(ref, doFn)
+		_ = walkSchemaRef(ref, doFn)
 	}
 
-	walkSchemaRef(ref.Value.AdditionalProperties, doFn)
+	_ = walkSchemaRef(ref.Value.AdditionalProperties, doFn)
 
 	return nil
 }
@@ -166,20 +166,20 @@ func walkParameterRef(ref *openapi3.ParameterRef, doFn func(RefWrapper) (bool, e
 		return nil
 	}
 
-	walkSchemaRef(ref.Value.Schema, doFn)
+	_ = walkSchemaRef(ref.Value.Schema, doFn)
 
 	for _, example := range ref.Value.Examples {
-		walkExampleRef(example, doFn)
+		_ = walkExampleRef(example, doFn)
 	}
 
 	for _, mediaType := range ref.Value.Content {
 		if mediaType == nil {
 			continue
 		}
-		walkSchemaRef(mediaType.Schema, doFn)
+		_ = walkSchemaRef(mediaType.Schema, doFn)
 
 		for _, example := range mediaType.Examples {
-			walkExampleRef(example, doFn)
+			_ = walkExampleRef(example, doFn)
 		}
 	}
 
@@ -207,10 +207,10 @@ func walkRequestBodyRef(ref *openapi3.RequestBodyRef, doFn func(RefWrapper) (boo
 		if mediaType == nil {
 			continue
 		}
-		walkSchemaRef(mediaType.Schema, doFn)
+		_ = walkSchemaRef(mediaType.Schema, doFn)
 
 		for _, example := range mediaType.Examples {
-			walkExampleRef(example, doFn)
+			_ = walkExampleRef(example, doFn)
 		}
 	}
 
@@ -235,22 +235,22 @@ func walkResponseRef(ref *openapi3.ResponseRef, doFn func(RefWrapper) (bool, err
 	}
 
 	for _, header := range ref.Value.Headers {
-		walkHeaderRef(header, doFn)
+		_ = walkHeaderRef(header, doFn)
 	}
 
 	for _, mediaType := range ref.Value.Content {
 		if mediaType == nil {
 			continue
 		}
-		walkSchemaRef(mediaType.Schema, doFn)
+		_ = walkSchemaRef(mediaType.Schema, doFn)
 
 		for _, example := range mediaType.Examples {
-			walkExampleRef(example, doFn)
+			_ = walkExampleRef(example, doFn)
 		}
 	}
 
 	for _, link := range ref.Value.Links {
-		walkLinkRef(link, doFn)
+		_ = walkLinkRef(link, doFn)
 	}
 
 	return nil
@@ -275,17 +275,17 @@ func walkCallbackRef(ref *openapi3.CallbackRef, doFn func(RefWrapper) (bool, err
 
 	for _, pathItem := range *ref.Value {
 		for _, parameter := range pathItem.Parameters {
-			walkParameterRef(parameter, doFn)
+			_ = walkParameterRef(parameter, doFn)
 		}
-		walkOperation(pathItem.Connect, doFn)
-		walkOperation(pathItem.Delete, doFn)
-		walkOperation(pathItem.Get, doFn)
-		walkOperation(pathItem.Head, doFn)
-		walkOperation(pathItem.Options, doFn)
-		walkOperation(pathItem.Patch, doFn)
-		walkOperation(pathItem.Post, doFn)
-		walkOperation(pathItem.Put, doFn)
-		walkOperation(pathItem.Trace, doFn)
+		_ = walkOperation(pathItem.Connect, doFn)
+		_ = walkOperation(pathItem.Delete, doFn)
+		_ = walkOperation(pathItem.Get, doFn)
+		_ = walkOperation(pathItem.Head, doFn)
+		_ = walkOperation(pathItem.Options, doFn)
+		_ = walkOperation(pathItem.Patch, doFn)
+		_ = walkOperation(pathItem.Post, doFn)
+		_ = walkOperation(pathItem.Put, doFn)
+		_ = walkOperation(pathItem.Trace, doFn)
 	}
 
 	return nil
@@ -308,7 +308,7 @@ func walkHeaderRef(ref *openapi3.HeaderRef, doFn func(RefWrapper) (bool, error))
 		return nil
 	}
 
-	walkSchemaRef(ref.Value.Schema, doFn)
+	_ = walkSchemaRef(ref.Value.Schema, doFn)
 
 	return nil
 }
@@ -380,7 +380,7 @@ func walkExampleRef(ref *openapi3.ExampleRef, doFn func(RefWrapper) (bool, error
 func findComponentRefs(swagger *openapi3.T) []string {
 	refs := []string{}
 
-	walkSwagger(swagger, func(ref RefWrapper) (bool, error) {
+	_ = walkSwagger(swagger, func(ref RefWrapper) (bool, error) {
 		if ref.Ref != "" {
 			refs = append(refs, ref.Ref)
 			return false, nil
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index bbba3fc..1843024 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -1,7 +1,6 @@
 package codegen
 
 import (
-	"errors"
 	"fmt"
 	"strings"
 
@@ -59,7 +58,7 @@ func (s *Schema) AddProperty(p Property) error {
 	// Scan all existing properties for a conflict
 	for _, e := range s.Properties {
 		if e.JsonFieldName == p.JsonFieldName && !PropertiesEqual(e, p) {
-			return errors.New(fmt.Sprintf("property '%s' already exists with a different type", e.JsonFieldName))
+			return fmt.Errorf("property '%s' already exists with a different type", e.JsonFieldName)
 		}
 	}
 	s.Properties = append(s.Properties, p)
@@ -421,7 +420,17 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 			enumValues[i] = fmt.Sprintf("%v", enumValue)
 		}
 
-		sanitizedValues := SanitizeEnumNames(enumValues)
+		enumNames := enumValues
+		for _, key := range []string{extEnumVarNames, extEnumNames} {
+			if _, ok := schema.ExtensionProps.Extensions[key]; ok {
+				if extEnumNames, err := extParseEnumVarNames(schema.ExtensionProps.Extensions[key]); err == nil {
+					enumNames = extEnumNames
+					break
+				}
+			}
+		}
+
+		sanitizedValues := SanitizeEnumNames(enumNames, enumValues)
 		outSchema.EnumValues = make(map[string]string, len(sanitizedValues))
 
 		for k, v := range sanitizedValues {
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index 7ef57f3..7585a26 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -22,11 +22,13 @@ import (
 
 	"github.com/deepmap/oapi-codegen/pkg/util"
 	"github.com/labstack/echo/v4"
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
 )
 
 const (
 	// These allow the case statements to be sorted later:
-	prefixMostSpecific, prefixLessSpecific, prefixLeastSpecific = "3", "6", "9"
+	prefixLeastSpecific = "9"
 
 	defaultClientTypeName = "Client"
 )
@@ -37,6 +39,8 @@ var (
 	contentTypesXML  = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"}
 
 	responseTypeSuffix = "Response"
+
+	titleCaser = cases.Title(language.English)
 )
 
 // This function takes an array of Parameter definition, and generates a valid
@@ -288,7 +292,7 @@ var TemplateFunctions = template.FuncMap{
 	"getResponseTypeDefinitions": getResponseTypeDefinitions,
 	"toStringArray":              toStringArray,
 	"lower":                      strings.ToLower,
-	"title":                      strings.Title,
+	"title":                      titleCaser.String,
 	"stripNewLines":              stripNewLines,
 	"sanitizeGoIdentity":         SanitizeGoIdentity,
 	"toGoComment":                StringWithTypeNameToGoComment,
diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl
index 8a37647..c83cc10 100644
--- a/pkg/codegen/templates/additional-properties.tmpl
+++ b/pkg/codegen/templates/additional-properties.tmpl
@@ -17,6 +17,7 @@ func (a *{{.TypeName}}) Set(fieldName string, value {{$addType}}) {
     a.AdditionalProperties[fieldName] = value
 }
 
+{{if eq 0 (len .Schema.UnionElements) -}}
 // Override default JSON handling for {{.TypeName}} to handle AdditionalProperties
 func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error {
     object := make(map[string]json.RawMessage)
@@ -68,3 +69,4 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
 	return json.Marshal(object)
 }
 {{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 bb4e8f7..e99bbeb 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -40,7 +40,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
   {{end}}
 
 {{range .SecurityDefinitions}}
-  ctx = context.WithValue(ctx, {{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+  ctx = context.WithValue(ctx, {{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
 {{end}}
 
   {{if .RequiresParamObject}}
diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl
index a3a0859..8fad876 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 | ucFirst}}Scopes = "{{$ProviderName}}.Scopes"
+    {{- $ProviderName | sanitizeGoIdentity | ucFirst}}Scopes = "{{$ProviderName}}.Scopes"
 {{end}}
 )
 {{end}}
diff --git a/pkg/codegen/templates/gin/gin-register.tmpl b/pkg/codegen/templates/gin/gin-register.tmpl
index 188cbb8..8f03722 100644
--- a/pkg/codegen/templates/gin/gin-register.tmpl
+++ b/pkg/codegen/templates/gin/gin-register.tmpl
@@ -6,15 +6,14 @@ type GinServerOptions struct {
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
-  return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+  RegisterHandlersWithOptions(router, si, GinServerOptions{})
 }
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-    {{if .}}
+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()})
@@ -27,8 +26,8 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
         ErrorHandler: errorHandler,
     }
     {{end}}
-    {{range .}}
+
+    {{range . -}}
     router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}})
-    {{end}}
-    return router
+    {{end -}}
 }
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index 3c11bcd..b16776b 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 | ucFirst}}Scopes, {{toStringArray .Scopes}})
+  c.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
 {{end}}
 
   {{if .RequiresParamObject}}
@@ -62,16 +62,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
           var value {{.TypeDef}}
           err = json.Unmarshal([]byte(paramValue), &value)
           if err != nil {
-            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %s", err), http.StatusBadRequest) {
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %s", err), http.StatusBadRequest)
             return
           }
 
           params.{{.GoName}} = {{if not .Required}}&{{end}}value
         {{end}}
         }{{if .Required}} else {
-           if !siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest) {
-             return
-           }
+           siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
+           return
         }{{end}}
       {{end}}
 
@@ -127,18 +126,19 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
     {{end}}
 
     {{range .CookieParams}}
-      var cookie *http.Cookie
+      {
+      var cookie string
 
       if cookie, err = c.Cookie("{{.ParamName}}"); err == nil {
 
       {{- if .IsPassThrough}}
-        params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+        params.{{.GoName}} = {{if not .Required}}&{{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 {
             siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'"), http.StatusBadRequest)
             return
@@ -155,7 +155,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
 
       {{- if .IsStyled}}
         var value {{.TypeDef}}
-        err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
+        err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
         if err != nil {
             siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %s", err), http.StatusBadRequest)
             return
@@ -170,6 +170,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         return
       }
       {{- end}}
+      }
     {{end}}
   {{end}}
 
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
index a72713b..1360891 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -40,7 +40,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
   {{end}}
 
 {{range .SecurityDefinitions}}
-  ctx = context.WithValue(ctx, {{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+  ctx = context.WithValue(ctx, {{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
 {{end}}
 
   {{if .RequiresParamObject}}
@@ -177,9 +177,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
     siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
 }
 
+  {{if opts.Compatibility.ApplyGorillaMiddlewareFirstToLast}}
+  for i := len(siw.HandlerMiddlewares) -1; i >= 0; i-- {
+    handler = siw.HandlerMiddlewares[i](handler)
+  }
+  {{else}}
   for _, middleware := range siw.HandlerMiddlewares {
     handler = middleware(handler)
   }
+  {{end}}
 
   handler(w, r.WithContext(ctx))
 }
@@ -253,4 +259,3 @@ type TooManyValuesForParamError struct {
 func (e *TooManyValuesForParamError) Error() string {
     return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
 }
-
diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl
new file mode 100644
index 0000000..79b4c67
--- /dev/null
+++ b/pkg/codegen/templates/union-and-additional-properties.tmpl
@@ -0,0 +1,72 @@
+{{range .Types}}
+
+{{$addType := .Schema.AdditionalPropertiesType.TypeDecl}}
+{{$typeName := .TypeName -}}
+{{$discriminator := .Schema.Discriminator}}
+{{$properties := .Schema.Properties -}}
+
+// Override default JSON handling for {{.TypeName}} to handle AdditionalProperties and union
+func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error {
+    err := a.union.UnmarshalJSON(b)
+    if err != nil {
+        return err
+    }
+    object := make(map[string]json.RawMessage)
+	err = json.Unmarshal(b, &object)
+	if err != nil {
+		return err
+	}
+{{range .Schema.Properties}}
+    if raw, found := object["{{.JsonFieldName}}"]; found {
+        err = json.Unmarshal(raw, &a.{{.GoFieldName}})
+        if err != nil {
+            return fmt.Errorf("error reading '{{.JsonFieldName}}': %w", err)
+        }
+        delete(object, "{{.JsonFieldName}}")
+    }
+{{end}}
+    if len(object) != 0 {
+        a.AdditionalProperties = make(map[string]{{$addType}})
+        for fieldName, fieldBuf := range object {
+            var fieldVal {{$addType}}
+            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 {{.TypeName}} to handle AdditionalProperties and union
+func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
+    var err error
+    b, err := a.union.MarshalJSON()
+    if err != nil {
+        return nil, err
+    }
+    object := make(map[string]json.RawMessage)
+    if a.union != nil {
+        err = json.Unmarshal(b, &object)
+        if err != nil {
+            return nil, err
+        }
+    }
+{{range .Schema.Properties}}
+{{if not .Required}}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}}
+{{end}}
+    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)
+}
+{{end}}
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index b758a82..06c91f4 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -86,6 +86,8 @@
         {{end}}
     {{end}}
 
+    {{if not .Schema.HasAdditionalProperties}}
+
     func (t {{.TypeName}}) MarshalJSON() ([]byte, error) {
         b, err := t.union.MarshalJSON()
         {{if ne 0 (len .Schema.Properties) -}}
@@ -134,4 +136,5 @@
         {{end -}}
         return err
     }
+    {{end}}
 {{end}}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 4339858..7526ee3 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -34,7 +34,7 @@ var (
 )
 
 func init() {
-	pathParamRE = regexp.MustCompile("{[.;?]?([^{}*]+)\\*?}")
+	pathParamRE = regexp.MustCompile(`{[.;?]?([^{}*]+)\*?}`)
 
 	predeclaredIdentifiers := []string{
 		// Types
@@ -554,13 +554,17 @@ func SanitizeGoIdentity(str string) string {
 
 // SanitizeEnumNames fixes illegal chars in the enum names
 // and removes duplicates
-func SanitizeEnumNames(enumNames []string) map[string]string {
-	dupCheck := make(map[string]int, len(enumNames))
-	deDup := make([]string, 0, len(enumNames))
-
-	for _, n := range enumNames {
+func SanitizeEnumNames(enumNames, enumValues []string) map[string]string {
+	dupCheck := make(map[string]int, len(enumValues))
+	deDup := make([][]string, 0, len(enumValues))
+
+	for i, v := range enumValues {
+		n := v
+		if i < len(enumNames) {
+			n = enumNames[i]
+		}
 		if _, dup := dupCheck[n]; !dup {
-			deDup = append(deDup, n)
+			deDup = append(deDup, []string{n, v})
 		}
 		dupCheck[n] = 0
 	}
@@ -568,13 +572,14 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
 	dupCheck = make(map[string]int, len(deDup))
 	sanitizedDeDup := make(map[string]string, len(deDup))
 
-	for _, n := range deDup {
+	for _, p := range deDup {
+		n, v := p[0], p[1]
 		sanitized := SanitizeGoIdentity(SchemaNameToTypeName(n))
 
 		if _, dup := dupCheck[sanitized]; !dup {
-			sanitizedDeDup[sanitized] = n
+			sanitizedDeDup[sanitized] = v
 		} else {
-			sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = n
+			sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = v
 		}
 		dupCheck[sanitized]++
 	}
diff --git a/pkg/gin-middleware/oapi_validate.go b/pkg/gin-middleware/oapi_validate.go
index e2097b6..3406134 100644
--- a/pkg/gin-middleware/oapi_validate.go
+++ b/pkg/gin-middleware/oapi_validate.go
@@ -18,6 +18,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"log"
 	"net/http"
 	"os"
 	"strings"
@@ -70,10 +71,16 @@ type Options struct {
 	ParamDecoder      openapi3filter.ContentParameterDecoder
 	UserData          interface{}
 	MultiErrorHandler MultiErrorHandler
+	// SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+	SilenceServersWarning bool
 }
 
 // OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
 func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) gin.HandlerFunc {
+	if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+		log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+	}
+
 	router, err := gorillamux.NewRouter(swagger)
 	if err != nil {
 		panic(err)
@@ -122,12 +129,12 @@ func ValidateRequestFromContext(c *gin.Context, router routers.Router, options *
 
 	// Pass the gin context into the request validator, so that any callbacks
 	// which it invokes make it available.
-	requestContext := context.WithValue(context.Background(), GinContextKey, c)
+	requestContext := context.WithValue(context.Background(), GinContextKey, c) //nolint:staticcheck
 
 	if options != nil {
 		validationInput.Options = &options.Options
 		validationInput.ParamDecoder = options.ParamDecoder
-		requestContext = context.WithValue(requestContext, UserDataKey, options.UserData)
+		requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
 	}
 
 	err = openapi3filter.ValidateRequest(requestContext, validationInput)
diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go
index 6a48a49..0318d29 100644
--- a/pkg/middleware/oapi_validate.go
+++ b/pkg/middleware/oapi_validate.go
@@ -18,6 +18,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"log"
 	"net/http"
 	"os"
 	"strings"
@@ -73,10 +74,16 @@ type Options struct {
 	UserData          interface{}
 	Skipper           echomiddleware.Skipper
 	MultiErrorHandler MultiErrorHandler
+	// SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
+	SilenceServersWarning bool
 }
 
 // OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
 func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) echo.MiddlewareFunc {
+	if swagger.Servers != nil && (options == nil || options.SilenceServersWarning) {
+		log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
+	}
+
 	router, err := gorillamux.NewRouter(swagger)
 	if err != nil {
 		panic(err)
@@ -130,12 +137,12 @@ func ValidateRequestFromContext(ctx echo.Context, router routers.Router, options
 
 	// Pass the Echo context into the request validator, so that any callbacks
 	// which it invokes make it available.
-	requestContext := context.WithValue(context.Background(), EchoContextKey, ctx)
+	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)
+		requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
 	}
 
 	err = openapi3filter.ValidateRequest(requestContext, validationInput)
diff --git a/pkg/runtime/bindform.go b/pkg/runtime/bindform.go
index b502f55..4f4fb76 100644
--- a/pkg/runtime/bindform.go
+++ b/pkg/runtime/bindform.go
@@ -99,7 +99,7 @@ func MarshalForm(ptr interface{}, encodings map[string]RequestBodyEncoding) (url
 		tag = strings.Split(tag, ",")[0] // extract the name of the tag
 		if encoding, ok := encodings[tag]; ok && encoding.ContentType != "" {
 			if strings.HasPrefix(encoding.ContentType, jsonContentType) {
-				if data, err := json.Marshal(field); err != nil {
+				if data, err := json.Marshal(field); err != nil { //nolint:staticcheck
 					return nil, err
 				} else {
 					result[tag] = append(result[tag], string(data))
@@ -131,7 +131,7 @@ func bindFormImpl(v reflect.Value, form map[string][]string, files map[string][]
 	case reflect.Slice:
 		if files := append(files[name], files[name+"[]"]...); len(files) != 0 {
 			if _, ok := v.Interface().([]types.File); ok {
-				result := make([]types.File, len(files), len(files))
+				result := make([]types.File, len(files))
 				for i, file := range files {
 					result[i].InitFromMultipart(file)
 				}
diff --git a/pkg/runtime/deepobject.go b/pkg/runtime/deepobject.go
index 54fc163..f18ace3 100644
--- a/pkg/runtime/deepobject.go
+++ b/pkg/runtime/deepobject.go
@@ -242,7 +242,8 @@ func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
 			tm, err = time.Parse(time.RFC3339Nano, pathValues.value)
 			if err != nil {
 				// Fall back to parsing it as a date.
-				tm, err = time.Parse(types.DateFormat, pathValues.value)
+				// TODO: why is this marked as an ineffassign?
+				tm, err = time.Parse(types.DateFormat, pathValues.value) //nolint:ineffassign,staticcheck
 				if err != nil {
 					return fmt.Errorf("error parsing tim as RFC3339 or 2006-01-02 time: %s", err)
 				}


Test patch:
diff --git a/internal/test/all_of/doc.go b/internal/test/all_of/doc.go
index 0740268..0388e17 100644
--- a/internal/test/all_of/doc.go
+++ b/internal/test/all_of/doc.go
@@ -1,4 +1,4 @@
-package all_of
+package allof
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config1.yaml openapi.yaml
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config2.yaml openapi.yaml
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index d7e23d3..4ed8b65 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -217,6 +217,13 @@ type OneOfObject120 = string
 // OneOfObject121 defines model for .
 type OneOfObject121 = float32
 
+// OneOfObject13 oneOf with fixed discriminator and other fields allowed
+type OneOfObject13 struct {
+	Type                 string                 `json:"type"`
+	AdditionalProperties map[string]interface{} `json:"-"`
+	union                json.RawMessage
+}
+
 // OneOfObject2 oneOf with inline elements
 type OneOfObject2 struct {
 	union json.RawMessage
@@ -772,6 +779,23 @@ func (a AdditionalPropertiesObject4_Inner) MarshalJSON() ([]byte, error) {
 	return json.Marshal(object)
 }
 
+// Getter for additional properties for OneOfObject13. Returns the specified
+// element and whether it was found
+func (a OneOfObject13) Get(fieldName string) (value interface{}, found bool) {
+	if a.AdditionalProperties != nil {
+		value, found = a.AdditionalProperties[fieldName]
+	}
+	return
+}
+
+// Setter for additional properties for OneOfObject13
+func (a *OneOfObject13) Set(fieldName string, value interface{}) {
+	if a.AdditionalProperties == nil {
+		a.AdditionalProperties = make(map[string]interface{})
+	}
+	a.AdditionalProperties[fieldName] = value
+}
+
 // AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4
 func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) {
 	var body OneOfVariant4
@@ -1248,6 +1272,89 @@ func (t *OneOfObject12) UnmarshalJSON(b []byte) error {
 	return err
 }
 
+// AsOneOfVariant1 returns the union data inside the OneOfObject13 as a OneOfVariant1
+func (t OneOfObject13) AsOneOfVariant1() (OneOfVariant1, error) {
+	var body OneOfVariant1
+	err := json.Unmarshal(t.union, &body)
+	return body, err
+}
+
+// FromOneOfVariant1 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant1
+func (t *OneOfObject13) FromOneOfVariant1(v OneOfVariant1) error {
+	t.Type = "v1"
+
+	b, err := json.Marshal(v)
+	t.union = b
+	return err
+}
+
+// MergeOneOfVariant1 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant1
+func (t *OneOfObject13) MergeOneOfVariant1(v OneOfVariant1) error {
+	t.Type = "v1"
+
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+// AsOneOfVariant6 returns the union data inside the OneOfObject13 as a OneOfVariant6
+func (t OneOfObject13) AsOneOfVariant6() (OneOfVariant6, error) {
+	var body OneOfVariant6
+	err := json.Unmarshal(t.union, &body)
+	return body, err
+}
+
+// FromOneOfVariant6 overwrites any union data inside the OneOfObject13 as the provided OneOfVariant6
+func (t *OneOfObject13) FromOneOfVariant6(v OneOfVariant6) error {
+	t.Type = "v6"
+
+	b, err := json.Marshal(v)
+	t.union = b
+	return err
+}
+
+// MergeOneOfVariant6 performs a merge with any union data inside the OneOfObject13, using the provided OneOfVariant6
+func (t *OneOfObject13) MergeOneOfVariant6(v OneOfVariant6) error {
+	t.Type = "v6"
+
+	b, err := json.Marshal(v)
+	if err != nil {
+		return err
+	}
+
+	merged, err := runtime.JsonMerge(b, t.union)
+	t.union = merged
+	return err
+}
+
+func (t OneOfObject13) Discriminator() (string, error) {
+	var discriminator struct {
+		Discriminator string `json:"type"`
+	}
+	err := json.Unmarshal(t.union, &discriminator)
+	return discriminator.Discriminator, err
+}
+
+func (t OneOfObject13) ValueByDiscriminator() (interface{}, error) {
+	discriminator, err := t.Discriminator()
+	if err != nil {
+		return nil, err
+	}
+	switch discriminator {
+	case "v1":
+		return t.AsOneOfVariant1()
+	case "v6":
+		return t.AsOneOfVariant6()
+	default:
+		return nil, errors.New("unknown discriminator value: " + discriminator)
+	}
+}
+
 // AsOneOfObject20 returns the union data inside the OneOfObject2 as a OneOfObject20
 func (t OneOfObject2) AsOneOfObject20() (OneOfObject20, error) {
 	var body OneOfObject20
@@ -1988,3 +2095,66 @@ func (t *OneOfObject9) UnmarshalJSON(b []byte) error {
 
 	return err
 }
+
+// Override default JSON handling for OneOfObject13 to handle AdditionalProperties and union
+func (a *OneOfObject13) UnmarshalJSON(b []byte) error {
+	err := a.union.UnmarshalJSON(b)
+	if err != nil {
+		return err
+	}
+	object := make(map[string]json.RawMessage)
+	err = json.Unmarshal(b, &object)
+	if err != nil {
+		return err
+	}
+
+	if raw, found := object["type"]; found {
+		err = json.Unmarshal(raw, &a.Type)
+		if err != nil {
+			return fmt.Errorf("error reading 'type': %w", err)
+		}
+		delete(object, "type")
+	}
+
+	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 OneOfObject13 to handle AdditionalProperties and union
+func (a OneOfObject13) MarshalJSON() ([]byte, error) {
+	var err error
+	b, err := a.union.MarshalJSON()
+	if err != nil {
+		return nil, err
+	}
+	object := make(map[string]json.RawMessage)
+	if a.union != nil {
+		err = json.Unmarshal(b, &object)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	object["type"], err = json.Marshal(a.Type)
+	if err != nil {
+		return nil, fmt.Errorf("error marshaling 'type': %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/components/components.yaml b/internal/test/components/components.yaml
index 79e3857..98224ed 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -325,6 +325,23 @@ components:
         - oneOf:
             - $ref: '#/components/schemas/OneOfVariant3'
             - $ref: '#/components/schemas/OneOfVariant4'
+    OneOfObject13:
+      description: oneOf with fixed discriminator and other fields allowed
+      type: object
+      properties:
+        type:
+          type: string
+      oneOf:
+        - $ref: '#/components/schemas/OneOfVariant1'
+        - $ref: '#/components/schemas/OneOfVariant6'
+      discriminator:
+        propertyName: type
+        mapping:
+          v1: '#/components/schemas/OneOfVariant1'
+          v6: '#/components/schemas/OneOfVariant6'
+      required:
+        - type
+      additionalProperties: true
     AnyOfObject1:
       description: simple anyOf case
       anyOf:
diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go
index a6fbbfd..e25ede2 100644
--- a/internal/test/components/components_test.go
+++ b/internal/test/components/components_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func assertJsonEqual(t *testing.T, j1 []byte, j2 []byte) {
@@ -87,7 +88,7 @@ func TestOneOf(t *testing.T) {
 	assert.NoError(t, err)
 	v2, err := dst.AsOneOfVariant2()
 	assert.NoError(t, err)
-	assert.Equal(t, OneOfVariant2([]int{1, 2, 3}), v2)
+	assert.Equal(t, []int{1, 2, 3}, v2)
 
 	err = json.Unmarshal([]byte(variant3), &dst)
 	assert.NoError(t, err)
@@ -203,6 +204,34 @@ func TestAnyOf(t *testing.T) {
 	assert.Equal(t, OneOfVariant5{Discriminator: "all", Id: 456}, v5)
 }
 
+func TestOneOfWithAdditional(t *testing.T) {
+	x := OneOfObject13{
+		AdditionalProperties: map[string]interface{}{"x": "y"},
+	}
+	err := x.MergeOneOfVariant1(OneOfVariant1{Name: "test-name"})
+	require.NoError(t, err)
+	b, err := json.Marshal(x)
+	require.NoError(t, err)
+	assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b))
+	var y OneOfObject13
+	err = json.Unmarshal(b, &y)
+	require.NoError(t, err)
+	assert.Equal(t, x.Type, y.Type)
+	xVariant, err := x.AsOneOfVariant1()
+	require.NoError(t, err)
+	yVariant, err := y.AsOneOfVariant1()
+	require.NoError(t, err)
+	assert.Equal(t, xVariant, yVariant)
+	xAdditional, ok := x.Get("x")
+	assert.True(t, ok)
+	yAdditional, ok := y.Get("x")
+	assert.True(t, ok)
+	assert.Equal(t, xAdditional, yAdditional)
+	b, err = json.Marshal(y)
+	require.NoError(t, err)
+	assert.JSONEq(t, `{"x":"y", "name":"test-name", "type":"v1"}`, string(b))
+}
+
 func TestMarshalWhenNoUnionValueSet(t *testing.T) {
 	const expected = `{}`
 
diff --git a/internal/test/externalref/imports_test.go b/internal/test/externalref/imports_test.go
index c3e326f..607def3 100644
--- a/internal/test/externalref/imports_test.go
+++ b/internal/test/externalref/imports_test.go
@@ -3,8 +3,8 @@ package externalref
 import (
 	"testing"
 
-	"github.com/deepmap/oapi-codegen/internal/test/externalref/packageA"
-	"github.com/deepmap/oapi-codegen/internal/test/externalref/packageB"
+	packageA "github.com/deepmap/oapi-codegen/internal/test/externalref/packageA"
+	packageB "github.com/deepmap/oapi-codegen/internal/test/externalref/packageB"
 	"github.com/stretchr/testify/require"
 )
 
diff --git a/internal/test/externalref/packageA/config.yaml b/internal/test/externalref/packageA/config.yaml
index cbd23be..03240de 100644
--- a/internal/test/externalref/packageA/config.yaml
+++ b/internal/test/externalref/packageA/config.yaml
@@ -1,4 +1,4 @@
-package: packageA
+package: packagea
 generate:
   models: true
   embedded-spec: true
diff --git a/internal/test/externalref/packageA/doc.go b/internal/test/externalref/packageA/doc.go
index 5054abe..8a7bb68 100644
--- a/internal/test/externalref/packageA/doc.go
+++ b/internal/test/externalref/packageA/doc.go
@@ -1,3 +1,3 @@
-package packageA
+package packagea
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go
index 01505b1..1a4d648 100644
--- a/internal/test/externalref/packageA/externalref.gen.go
+++ b/internal/test/externalref/packageA/externalref.gen.go
@@ -1,7 +1,7 @@
-// Package packageA provides primitives to interact with the openapi HTTP API.
+// Package packagea provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package packageA
+package packagea
 
 import (
 	"bytes"
diff --git a/internal/test/externalref/packageB/config.yaml b/internal/test/externalref/packageB/config.yaml
index 72752cd..748a188 100644
--- a/internal/test/externalref/packageB/config.yaml
+++ b/internal/test/externalref/packageB/config.yaml
@@ -1,4 +1,4 @@
-package: packageB
+package: packageb
 generate:
   models: true
   embedded-spec: true
diff --git a/internal/test/externalref/packageB/doc.go b/internal/test/externalref/packageB/doc.go
index fdee47d..73641da 100644
--- a/internal/test/externalref/packageB/doc.go
+++ b/internal/test/externalref/packageB/doc.go
@@ -1,3 +1,3 @@
-package packageB
+package packageb
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/externalref/packageB/externalref.gen.go b/internal/test/externalref/packageB/externalref.gen.go
index aa545f1..3e4fe05 100644
--- a/internal/test/externalref/packageB/externalref.gen.go
+++ b/internal/test/externalref/packageB/externalref.gen.go
@@ -1,7 +1,7 @@
-// Package packageB provides primitives to interact with the openapi HTTP API.
+// Package packageb provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package packageB
+package packageb
 
 import (
 	"bytes"
diff --git a/internal/test/issues/issue-312/config.yaml b/internal/test/issues/issue-312/config.yaml
index f3d72fb..a0db7e9 100644
--- a/internal/test/issues/issue-312/config.yaml
+++ b/internal/test/issues/issue-312/config.yaml
@@ -1,4 +1,4 @@
-package: issue_312
+package: issue312
 generate:
   echo-server: true
   client: true
diff --git a/internal/test/issues/issue-312/doc.go b/internal/test/issues/issue-312/doc.go
index c27d53b..8eb982d 100644
--- a/internal/test/issues/issue-312/doc.go
+++ b/internal/test/issues/issue-312/doc.go
@@ -1,3 +1,3 @@
-package issue_312
+package issue312
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index 0285217..c077475 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -1,7 +1,7 @@
-// Package issue_312 provides primitives to interact with the openapi HTTP API.
+// Package issue312 provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package issue_312
+package issue312
 
 import (
 	"bytes"
diff --git a/internal/test/issues/issue-312/issue_test.go b/internal/test/issues/issue-312/issue_test.go
index 2bf46d8..23a1464 100644
--- a/internal/test/issues/issue-312/issue_test.go
+++ b/internal/test/issues/issue-312/issue_test.go
@@ -1,4 +1,4 @@
-package issue_312
+package issue312
 
 import (
 	"context"
@@ -26,7 +26,8 @@ func TestClient_WhenPathHasColon_RequestHasCorrectPath(t *testing.T) {
 		assert.Equal(t, "http://host/pets:validate", req.URL.String())
 	})
 
-	client.ValidatePetsWithResponse(context.Background(), ValidatePetsJSONRequestBody{
+	// TODO: this err should be checked, but it defaults to returning the "something went wrong", so we should refactor accordingly
+	_, _ = client.ValidatePetsWithResponse(context.Background(), ValidatePetsJSONRequestBody{
 		Names: []string{"fido"},
 	})
 	doer.AssertExpectations(t)
@@ -43,7 +44,8 @@ func TestClient_WhenPathHasId_RequestHasCorrectPath(t *testing.T) {
 		assert.Equal(t, "/pets/id", req.URL.Path)
 	})
 	petID := "id"
-	client.GetPetWithResponse(context.Background(), petID)
+	// TODO: this err should be checked, but it defaults to returning the "something went wrong", so we should refactor accordingly
+	_, _ = client.GetPetWithResponse(context.Background(), petID)
 	doer.AssertExpectations(t)
 }
 
@@ -58,7 +60,8 @@ func TestClient_WhenPathHasIdContainingReservedCharacter_RequestHasCorrectPath(t
 		assert.Equal(t, "http://host/pets/id1%2Fid2", req.URL.String())
 	})
 	petID := "id1/id2"
-	client.GetPetWithResponse(context.Background(), petID)
+	// TODO: this err should be checked, but it defaults to returning the "something went wrong", so we should refactor accordingly
+	_, _ = client.GetPetWithResponse(context.Background(), petID)
 	doer.AssertExpectations(t)
 }
 
diff --git a/internal/test/issues/issue-52/config.yaml b/internal/test/issues/issue-52/config.yaml
index 1aa56b1..8ea198f 100644
--- a/internal/test/issues/issue-52/config.yaml
+++ b/internal/test/issues/issue-52/config.yaml
@@ -1,4 +1,4 @@
-package: issue_52
+package: issue52
 generate:
   echo-server: true
   client: true
diff --git a/internal/test/issues/issue-52/doc.go b/internal/test/issues/issue-52/doc.go
index 2f19f47..f29e0e9 100644
--- a/internal/test/issues/issue-52/doc.go
+++ b/internal/test/issues/issue-52/doc.go
@@ -1,3 +1,3 @@
-package issue_52
+package issue52
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index fde84ba..d3f1a23 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -1,7 +1,7 @@
-// Package issue_52 provides primitives to interact with the openapi HTTP API.
+// Package issue52 provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package issue_52
+package issue52
 
 import (
 	"bytes"
diff --git a/internal/test/issues/issue-52/issue_test.go b/internal/test/issues/issue-52/issue_test.go
index 12edb76..0d90bf6 100644
--- a/internal/test/issues/issue-52/issue_test.go
+++ b/internal/test/issues/issue-52/issue_test.go
@@ -1,4 +1,4 @@
-package issue_52
+package issue52
 
 import (
 	_ "embed"
@@ -17,7 +17,7 @@ func TestIssue(t *testing.T) {
 	require.NoError(t, err)
 
 	opts := codegen.Configuration{
-		PackageName: "issue_52",
+		PackageName: "issue52",
 		Generate: codegen.GenerateOptions{
 			EchoServer:   true,
 			Client:       true,
diff --git a/internal/test/issues/issue-579/gen.go b/internal/test/issues/issue-579/gen.go
index a91277b..d34774f 100644
--- a/internal/test/issues/issue-579/gen.go
+++ b/internal/test/issues/issue-579/gen.go
@@ -1,3 +1,3 @@
-package issue_579
+package issue579
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=issue_579 --generate=types,skip-prune --alias-types -o issue.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=issue579 --generate=types,skip-prune --alias-types -o issue.gen.go spec.yaml
diff --git a/internal/test/issues/issue-579/issue.gen.go b/internal/test/issues/issue-579/issue.gen.go
index 93cc60a..b7284ff 100644
--- a/internal/test/issues/issue-579/issue.gen.go
+++ b/internal/test/issues/issue-579/issue.gen.go
@@ -1,7 +1,7 @@
-// Package issue_579 provides primitives to interact with the openapi HTTP API.
+// Package issue579 provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package issue_579
+package issue579
 
 import (
 	openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
diff --git a/internal/test/issues/issue-579/issue_test.go b/internal/test/issues/issue-579/issue_test.go
index 4c1b901..7c92a42 100644
--- a/internal/test/issues/issue-579/issue_test.go
+++ b/internal/test/issues/issue-579/issue_test.go
@@ -1,4 +1,4 @@
-package issue_579
+package issue579
 
 import (
 	"encoding/json"
diff --git a/internal/test/issues/issue-grab_import_names/config.yaml b/internal/test/issues/issue-grab_import_names/config.yaml
index 7327e2a..3248a48 100644
--- a/internal/test/issues/issue-grab_import_names/config.yaml
+++ b/internal/test/issues/issue-grab_import_names/config.yaml
@@ -1,4 +1,4 @@
-package: grab_import_names
+package: grabimportnames
 generate:
   echo-server: true
   client: true
diff --git a/internal/test/issues/issue-grab_import_names/doc.go b/internal/test/issues/issue-grab_import_names/doc.go
index 0762ddb..5c73385 100644
--- a/internal/test/issues/issue-grab_import_names/doc.go
+++ b/internal/test/issues/issue-grab_import_names/doc.go
@@ -1,3 +1,3 @@
-package grab_import_names
+package grabimportnames
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index 275e6a7..6378e57 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -1,7 +1,7 @@
-// Package grab_import_names provides primitives to interact with the openapi HTTP API.
+// Package grabimportnames provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package grab_import_names
+package grabimportnames
 
 import (
 	"bytes"
diff --git a/internal/test/issues/issue-grab_import_names/issue_test.go b/internal/test/issues/issue-grab_import_names/issue_test.go
index c00b42d..8dffcd2 100644
--- a/internal/test/issues/issue-grab_import_names/issue_test.go
+++ b/internal/test/issues/issue-grab_import_names/issue_test.go
@@ -1,4 +1,4 @@
-package grab_import_names
+package grabimportnames
 
 import (
 	"testing"
@@ -13,7 +13,7 @@ func TestLineComments(t *testing.T) {
 	require.NoError(t, err)
 
 	opts := codegen.Configuration{
-		PackageName: "grab_import_names",
+		PackageName: "grabimportnames",
 		Generate: codegen.GenerateOptions{
 			EchoServer:   true,
 			Client:       true,
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/config.yaml b/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
index f3709ac..1f7ce9d 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
+++ b/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
@@ -1,5 +1,5 @@
 ---
-package: head_digit_of_httpheader
+package: headdigitofhttpheader
 generate:
   strict-server: true
 output: issue.gen.go
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/doc.go b/internal/test/issues/issue-head-digit-of-httpheader/doc.go
index 4a2cdf8..0c4cfc1 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/doc.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/doc.go
@@ -1,3 +1,3 @@
-package head_digit_of_httpheader
+package headdigitofhttpheader
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
index c512e7a..703c262 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
@@ -1,7 +1,7 @@
-// Package head_digit_of_httpheader provides primitives to interact with the openapi HTTP API.
+// Package headdigitofhttpheader provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package head_digit_of_httpheader
+package headdigitofhttpheader
 
 import (
 	"context"
diff --git a/internal/test/issues/issue-illegal_enum_names/config.yaml b/internal/test/issues/issue-illegal_enum_names/config.yaml
index 592a3cb..9b426a0 100644
--- a/internal/test/issues/issue-illegal_enum_names/config.yaml
+++ b/internal/test/issues/issue-illegal_enum_names/config.yaml
@@ -1,4 +1,4 @@
-package: illegal_enum_names
+package: illegalenumnames
 generate:
   echo-server: true
   client: true
diff --git a/internal/test/issues/issue-illegal_enum_names/doc.go b/internal/test/issues/issue-illegal_enum_names/doc.go
index 4bc0db2..de0c23f 100644
--- a/internal/test/issues/issue-illegal_enum_names/doc.go
+++ b/internal/test/issues/issue-illegal_enum_names/doc.go
@@ -1,3 +1,3 @@
-package illegal_enum_names
+package illegalenumnames
 
 //go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
index 6a81336..3f0d8e0 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -1,7 +1,7 @@
-// Package illegal_enum_names provides primitives to interact with the openapi HTTP API.
+// Package illegalenumnames provides primitives to interact with the openapi HTTP API.
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
-package illegal_enum_names
+package illegalenumnames
 
 import (
 	"bytes"
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 4d7c2c8..3df57c8 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue_test.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go
@@ -1,4 +1,4 @@
-package illegal_enum_names
+package illegalenumnames
 
 import (
 	"go/ast"
@@ -16,7 +16,7 @@ func TestIllegalEnumNames(t *testing.T) {
 	require.NoError(t, err)
 
 	opts := codegen.Configuration{
-		PackageName: "illegal_enum_names",
+		PackageName: "illegalenumnames",
 		Generate: codegen.GenerateOptions{
 			EchoServer:   true,
 			Client:       true,
diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go
index d4007e0..5b70268 100644
--- a/internal/test/strict-server/echo/server.go
+++ b/internal/test/strict-server/echo/server.go
@@ -94,7 +94,7 @@ func (s StrictServer) URLEncodedExample(ctx context.Context, request URLEncodedE
 }
 
 func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) {
-	return HeadersExample200JSONResponse{Body: Example(*request.Body), Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
+	return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
 }
 
 func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go
index 52c7290..a00437d 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -208,15 +208,13 @@ type GinServerOptions struct {
 }
 
 // RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
-func RegisterHandlers(router *gin.Engine, si ServerInterface) *gin.Engine {
-	return RegisterHandlersWithOptions(router, si, GinServerOptions{})
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+	RegisterHandlersWithOptions(router, si, GinServerOptions{})
 }
 
 // RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
-
+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()})
@@ -230,24 +228,14 @@ func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options
 	}
 
 	router.POST(options.BaseURL+"/json", wrapper.JSONExample)
-
 	router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample)
-
 	router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
-
 	router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
-
 	router.POST(options.BaseURL+"/text", wrapper.TextExample)
-
 	router.POST(options.BaseURL+"/unknown", wrapper.UnknownExample)
-
 	router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
-
 	router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
-
 	router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample)
-
-	return router
 }
 
 type BadrequestResponse struct {
diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go
index 0075f32..860cc4c 100644
--- a/internal/test/strict-server/strict_test.go
+++ b/internal/test/strict-server/strict_test.go
@@ -1,4 +1,4 @@
-package strict_server
+package strictserver
 
 import (
 	"bytes"
@@ -11,16 +11,17 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/gin-gonic/gin"
+	"github.com/go-chi/chi/v5"
+	"github.com/labstack/echo/v4"
+	"github.com/stretchr/testify/assert"
+
 	"github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
 	api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
 	api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
 	api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
 	"github.com/deepmap/oapi-codegen/pkg/runtime"
 	"github.com/deepmap/oapi-codegen/pkg/testutil"
-	"github.com/gin-gonic/gin"
-	"github.com/go-chi/chi/v5"
-	"github.com/labstack/echo/v4"
-	"github.com/stretchr/testify/assert"
 )
 
 func TestChiServer(t *testing.T) {
@@ -44,8 +45,8 @@ func TestGinServer(t *testing.T) {
 	strictHandler := api2.NewStrictHandler(server, nil)
 	gin.SetMode(gin.ReleaseMode)
 	r := gin.New()
-	handler := api2.RegisterHandlers(r, strictHandler)
-	testImpl(t, handler)
+	api2.RegisterHandlers(r, strictHandler)
+	testImpl(t, r)
 }
 
 func testImpl(t *testing.T, handler http.Handler) {
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index 4a85eb1..e3878f5 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -188,6 +188,11 @@ type GetTestByNameResponse struct {
 	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, "type EnumTestNumerics int")
+	assert.Contains(t, code, "N2 EnumTestNumerics = 2")
+	assert.Contains(t, code, "type EnumTestEnumNames int")
+	assert.Contains(t, code, "Two  EnumTestEnumNames = 2")
+	assert.Contains(t, code, "Double EnumTestEnumVarnames = 2")
 
 	// Make sure the generated code is valid:
 	checkLint(t, "test.gen.go", []byte(code))
diff --git a/pkg/codegen/test_spec.yaml b/pkg/codegen/test_spec.yaml
index 62a9871..7491c69 100644
--- a/pkg/codegen/test_spec.yaml
+++ b/pkg/codegen/test_spec.yaml
@@ -87,6 +87,27 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/Error'
+  /enum:
+    get:
+      tags:
+        - enum
+      summary: References enum
+      operationId: getEnum
+      responses:
+        200:
+          description: Success
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/EnumTest'
+        default:
+          description: Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
 
 components:
   schemas:
@@ -136,3 +157,23 @@ components:
         cause:
           type: string
           enum: [ car, dog, oldage ]
+
+    EnumTest:
+      properties:
+        numerics:
+          type: integer
+          enum: [0, 1, 2]
+        enumNames:
+          type: integer
+          enum: [0, 1, 2]
+          x-enumNames:
+            - zero
+            - one
+            - two
+        enumVarnames:
+          type: integer
+          enum: [0, 1, 2]
+          x-enum-varnames:
+            - na
+            - single
+            - double
diff --git a/pkg/runtime/bindform_test.go b/pkg/runtime/bindform_test.go
index 9660ce4..159cef2 100644
--- a/pkg/runtime/bindform_test.go
+++ b/pkg/runtime/bindform_test.go
@@ -29,7 +29,7 @@ func TestBindURLForm(t *testing.T) {
 		OptStruct       *testSubStruct   `json:"opt_struct,omitempty"`
 		OptStructSlice  *[]testSubStruct `json:"opt_struct_slice,omitempty"`
 		NotSerializable int              `json:"-"`
-		unexported      int
+		unexported      int              //nolint:unused
 	}
 
 	testCases := map[string]testStruct{
@@ -137,7 +137,7 @@ func TestMarshalForm(t *testing.T) {
 		OptStruct       *testSubStruct   `json:"opt_struct,omitempty"`
 		OptStructSlice  *[]testSubStruct `json:"opt_struct_slice,omitempty"`
 		NotSerializable int              `json:"-"`
-		unexported      int
+		unexported      int              //nolint:unused
 	}
 
 	testCases := map[string]testStruct{
diff --git a/pkg/runtime/styleparam_test.go b/pkg/runtime/styleparam_test.go
index 5500820..1943ae0 100644
--- a/pkg/runtime/styleparam_test.go
+++ b/pkg/runtime/styleparam_test.go
@@ -394,10 +394,10 @@ func TestStyleParam(t *testing.T) {
 
 	// ------------------------  spaceDelimited Style --------------------------
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
 	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, array)
@@ -408,60 +408,60 @@ func TestStyleParam(t *testing.T) {
 	assert.NoError(t, err)
 	assert.EqualValues(t, "id=3&id=4&id=5", result)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, object)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, object)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, object)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, object)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, dict)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, dict)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, dict)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, dict)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
 	// -------------------------  pipeDelimited Style --------------------------
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
 	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, array)
@@ -472,69 +472,69 @@ func TestStyleParam(t *testing.T) {
 	assert.NoError(t, err)
 	assert.EqualValues(t, "id=3&id=4&id=5", result)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, object)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, object)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, object)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, object)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, dict)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, dict)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, dict)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, dict)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
 	// ---------------------------  deepObject Style ---------------------------
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, primitive)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, primitive)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, array)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, array)
 	assert.Error(t, err)
 
 	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, array)
 	assert.NoError(t, err)
 	assert.EqualValues(t, "id[0]=3&id[1]=4&id[2]=5", result)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, object)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, object)
 	assert.Error(t, err)
 
 	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, object)
@@ -545,40 +545,40 @@ func TestStyleParam(t *testing.T) {
 	assert.NoError(t, err)
 	assert.EqualValues(t, "id[firstName]=Alex&id[role]=admin", result)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, timestamp)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &timestamp)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &timestamp)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, date)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &date)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &date)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, aUUID)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
-	result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &aUUID)
+	_, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &aUUID)
 	assert.Error(t, err)
 
 	// Misc tests
diff --git a/pkg/types/file_test.go b/pkg/types/file_test.go
index 3e66c7d..fb4ce98 100644
--- a/pkg/types/file_test.go
+++ b/pkg/types/file_test.go
@@ -48,6 +48,7 @@ func TestFileJSON(t *testing.T) {
 	err = json.Unmarshal(buf, &o4)
 	require.NoError(t, err)
 	o4Bytes, err := o4.BinaryFieldPtr.Bytes()
+	require.NoError(t, err)
 	assert.Equal(t, []byte("hello"), o4Bytes)
 
 }