Repository: deepmap/oapi-codegen
Pull request #578 (2022-05-19 12:54:28)

chi : Change the signature of the `MiddlewareFunc` for compatibilities.
This PR changes the signature of the `MiddlewareFunc` for chi, and get more compatibility in the ecosystem.

Before:

```
type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
```

Now:

```
type MiddlewareFunc func(http.Handler) http.Handler
```

Almost another famous middleware libraries for `net/http` in Go has a function signature below.

For example,
- [go-chi/chi/middleware](https://pkg.go.dev/github.com/go-chi/chi/middleware)
- [rs/cors](https://github.com/rs/cors/blob/a4a5ce87d5a262d09854a195cb6cb1ba1e28c352/cors.go#L219)
- [auth0/go-jwt-middleware](https://github.com/auth0/go-jwt-middleware/blob/e82be78f2661fe7f35dbe798d7c42bcedaf45f52/middleware.go#L50)
- And many more...




uhey22e: Related issue #286 

As @deepmap-marcinr said, this PR breaks people's code.
But that's not a big deal, IMHO.

There is an easy work-around to fix the template version.
Following command runs oapi-codegen with version written in the `go.mod` file. So, developers can put breaking changes on ice for some time.

```
go run -mod=mod github.com/deepmap/oapi-codegen/cmd/oapi-codegen
```


Patch:
diff --git a/README.md b/README.md
index 0bf46d9..d7297bd 100644
--- a/README.md
+++ b/README.md
@@ -255,6 +255,9 @@ func SetupHandler() {
     http.Handle("/", Handler(&myApi))
 }
 ```
+
+Alternatively, [Gorilla](https://github.com/gorilla/mux) is also 100% compatible with `net/http` and can be generated with `-generate gorilla`.
+
 </summary></details>
 
 #### Additional Properties in type definitions
diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go
index 43d8b82..fc1b6cf 100644
--- a/cmd/oapi-codegen/oapi-codegen.go
+++ b/cmd/oapi-codegen/oapi-codegen.go
@@ -19,7 +19,6 @@ import (
 	"io/ioutil"
 	"os"
 	"path"
-	"path/filepath"
 	"runtime/debug"
 	"strings"
 
@@ -35,53 +34,67 @@ func errExit(format string, args ...interface{}) {
 }
 
 var (
-	flagPackageName        string
+	flagOutputFile     string
+	flagConfigFile     string
+	flagOldConfigStyle bool
+	flagOutputConfig   bool
+	flagPrintVersion   bool
+	flagPackageName    string
+
+	// The options below are deprecated, and they will be removed in a future
+	// release. Please use the new config file format.
 	flagGenerate           string
-	flagOutputFile         string
 	flagIncludeTags        string
 	flagExcludeTags        string
 	flagTemplatesDir       string
 	flagImportMapping      string
 	flagExcludeSchemas     string
-	flagConfigFile         string
 	flagResponseTypeSuffix string
 	flagAliasTypes         bool
-	flagPrintVersion       bool
-	flagOldAllOfOutput     bool
-	flagOldEnumConflicts   bool
 )
 
 type configuration struct {
-	PackageName        string            `yaml:"package"`
-	GenerateTargets    []string          `yaml:"generate"`
-	OutputFile         string            `yaml:"output"`
-	IncludeTags        []string          `yaml:"include-tags"`
-	ExcludeTags        []string          `yaml:"exclude-tags"`
-	TemplatesDir       string            `yaml:"templates"`
-	ImportMapping      map[string]string `yaml:"import-mapping"`
-	ExcludeSchemas     []string          `yaml:"exclude-schemas"`
-	OldAllOfOutput     bool              `yaml:"old-all-of-output"`
-	OldEnumConflicts   bool              `yaml:"old-enum-conflicts"`
-	ResponseTypeSuffix string            `yaml:"response-type-suffix"`
+	codegen.Configuration `yaml:",inline"`
+
+	// OutputFile is the filename to output.
+	OutputFile string `yaml:"output,omitempty"`
 }
 
-func main() {
+// This structure is deprecated. Please add no more flags here. It is here
+// for backwards compatibility and it will be removed in the future.
+type oldConfiguration struct {
+	PackageName        string                       `yaml:"package"`
+	GenerateTargets    []string                     `yaml:"generate"`
+	OutputFile         string                       `yaml:"output"`
+	IncludeTags        []string                     `yaml:"include-tags"`
+	ExcludeTags        []string                     `yaml:"exclude-tags"`
+	TemplatesDir       string                       `yaml:"templates"`
+	ImportMapping      map[string]string            `yaml:"import-mapping"`
+	ExcludeSchemas     []string                     `yaml:"exclude-schemas"`
+	ResponseTypeSuffix string                       `yaml:"response-type-suffix"`
+	Compatibility      codegen.CompatibilityOptions `yaml:"compatibility"`
+}
 
+func main() {
+	flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default")
+	flag.BoolVar(&flagOldConfigStyle, "old-config-style", false, "whether to use the older style config file format")
+	flag.BoolVar(&flagOutputConfig, "output-config", false, "when true, outputs a configuration file for oapi-codegen using current settings")
+	flag.StringVar(&flagConfigFile, "config", "", "a YAML config file that controls oapi-codegen behavior")
+	flag.BoolVar(&flagPrintVersion, "version", false, "when specified, print version and exit")
 	flag.StringVar(&flagPackageName, "package", "", "The package name for generated code")
+
+	// All flags below are deprecated, and will be removed in a future release. Please do not
+	// update their behavior.
 	flag.StringVar(&flagGenerate, "generate", "types,client,server,spec",
-		`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "spec", "skip-fmt", "skip-prune"`)
-	flag.StringVar(&flagOutputFile, "o", "", "Where to output generated code, stdout is default")
+		`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune"`)
 	flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
 	flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
 	flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates")
 	flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path")
 	flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation")
-	flag.StringVar(&flagConfigFile, "config", "", "a YAML config file that controls oapi-codegen behavior")
 	flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "the suffix used for responses types")
 	flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible")
-	flag.BoolVar(&flagPrintVersion, "version", false, "when specified, print version and exit")
-	flag.BoolVar(&flagOldAllOfOutput, "old-all-of-output", false, "when true, old and incorrect AllOf implementation is used")
-	flag.BoolVar(&flagOldEnumConflicts, "old-enum-conflicts", false, "when true, use old style enum naming")
+
 	flag.Parse()
 
 	if flagPrintVersion {
@@ -100,53 +113,56 @@ func main() {
 		os.Exit(1)
 	}
 
-	cfg := configFromFlags()
-
-	// If the package name has not been specified, we will use the name of the
-	// swagger file.
-	if cfg.PackageName == "" {
-		path := flag.Arg(0)
-		baseName := filepath.Base(path)
-		// Split the base name on '.' to get the first part of the file.
-		nameParts := strings.Split(baseName, ".")
-		cfg.PackageName = codegen.ToCamelCase(nameParts[0])
-	}
-
-	opts := codegen.Options{
-		AliasTypes:         flagAliasTypes,
-		ResponseTypeSuffix: flagResponseTypeSuffix,
-	}
-	for _, g := range cfg.GenerateTargets {
-		switch g {
-		case "client":
-			opts.GenerateClient = true
-		case "chi-server":
-			opts.GenerateChiServer = true
-		case "server":
-			opts.GenerateEchoServer = true
-		case "gin":
-			opts.GenerateGinServer = true
-		case "types":
-			opts.GenerateTypes = true
-		case "spec":
-			opts.EmbedSpec = true
-		case "skip-fmt":
-			opts.SkipFmt = true
-		case "skip-prune":
-			opts.SkipPrune = true
-		default:
-			fmt.Printf("unknown generate option %s\n", g)
-			flag.PrintDefaults()
-			os.Exit(1)
+	var opts configuration
+	if !flagOldConfigStyle {
+		// We simply read the configuration from disk.
+		if flagConfigFile != "" {
+			buf, err := ioutil.ReadFile(flagConfigFile)
+			if err != nil {
+				errExit("error reading config file '%s': %v", flagConfigFile, err)
+			}
+			err = yaml.Unmarshal(buf, &opts)
+			if err != nil {
+				errExit("error parsing'%s' as YAML: %v", flagConfigFile, err)
+			}
+		}
+		var err error
+		opts, err = updateConfigFromFlags(opts)
+		if err != nil {
+			errExit("error processing flags: %v", err)
 		}
+	} else {
+		var oldConfig oldConfiguration
+		if flagConfigFile != "" {
+			buf, err := ioutil.ReadFile(flagConfigFile)
+			if err != nil {
+				errExit("error reading config file '%s': %v", flagConfigFile, err)
+			}
+			err = yaml.Unmarshal(buf, &oldConfig)
+			if err != nil {
+				errExit("error parsing'%s' as YAML: %v", flagConfigFile, err)
+			}
+		}
+		opts = newConfigFromOldConfig(oldConfig)
 	}
 
-	opts.IncludeTags = cfg.IncludeTags
-	opts.ExcludeTags = cfg.ExcludeTags
-	opts.ExcludeSchemas = cfg.ExcludeSchemas
+	// Ensure default values are set if user hasn't specified some needed
+	// fields.
+	opts.Configuration = opts.UpdateDefaults()
 
-	if opts.GenerateEchoServer && opts.GenerateChiServer {
-		errExit("can not specify both server and chi-server targets simultaneously")
+	// Now, ensure that the config options are valid.
+	if err := opts.Validate(); err != nil {
+		errExit("configuration error: %v", err)
+	}
+
+	// If the user asked to output configuration, output it to stdout and exit
+	if flagOutputConfig {
+		buf, err := yaml.Marshal(opts)
+		if err != nil {
+			errExit("error YAML marshaling configuration: %v", err)
+		}
+		fmt.Print(string(buf))
+		return
 	}
 
 	swagger, err := util.LoadSwagger(flag.Arg(0))
@@ -154,25 +170,13 @@ func main() {
 		errExit("error loading swagger spec in %s\n: %s", flag.Arg(0), err)
 	}
 
-	templates, err := loadTemplateOverrides(cfg.TemplatesDir)
-	if err != nil {
-		errExit("error loading template overrides: %s\n", err)
-	}
-	opts.UserTemplates = templates
-
-	opts.ImportMapping = cfg.ImportMapping
-
-	opts.OldMergeSchemas = cfg.OldAllOfOutput
-
-	opts.OldEnumConflicts = cfg.OldEnumConflicts
-
-	code, err := codegen.Generate(swagger, cfg.PackageName, opts)
+	code, err := codegen.Generate(swagger, opts.Configuration)
 	if err != nil {
 		errExit("error generating code: %s\n", err)
 	}
 
-	if cfg.OutputFile != "" {
-		err = ioutil.WriteFile(cfg.OutputFile, []byte(code), 0644)
+	if opts.OutputFile != "" {
+		err = ioutil.WriteFile(opts.OutputFile, []byte(code), 0644)
 		if err != nil {
 			errExit("error writing generated code to file: %s", err)
 		}
@@ -217,25 +221,54 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
 	return templates, nil
 }
 
-// configFromFlags parses the flags and the config file. Anything which is
-// a zerovalue in the configuration file will be replaced with the flag
-// value, this means that the config file overrides flag values.
-func configFromFlags() *configuration {
-	var cfg configuration
+// 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
+func updateConfigFromFlags(cfg configuration) (configuration, error) {
+	if flagPackageName != "" {
+		cfg.PackageName = flagPackageName
+	}
 
-	// Load the configuration file first.
-	if flagConfigFile != "" {
-		f, err := os.Open(flagConfigFile)
-		if err != nil {
-			errExit("failed to open config file with error: %v\n", err)
-		}
-		defer f.Close()
-		err = yaml.NewDecoder(f).Decode(&cfg)
-		if err != nil {
-			errExit("error parsing config file: %v\n", err)
-		}
+	var unsupportedFlags []string
+
+	if flagGenerate != "types,client,server,spec" {
+		unsupportedFlags = append(unsupportedFlags, "--generate")
+	}
+	if flagIncludeTags != "" {
+		unsupportedFlags = append(unsupportedFlags, "--include-tags")
+	}
+	if flagExcludeTags != "" {
+		unsupportedFlags = append(unsupportedFlags, "--exclude-tags")
+	}
+	if flagTemplatesDir != "" {
+		unsupportedFlags = append(unsupportedFlags, "--templates")
+	}
+	if flagImportMapping != "" {
+		unsupportedFlags = append(unsupportedFlags, "--import-mapping")
+	}
+	if flagExcludeSchemas != "" {
+		unsupportedFlags = append(unsupportedFlags, "--exclude-schemas")
+	}
+	if flagResponseTypeSuffix != "" {
+		unsupportedFlags = append(unsupportedFlags, "--response-type-suffix")
+	}
+	if flagAliasTypes {
+		unsupportedFlags = append(unsupportedFlags, "--alias-types")
 	}
 
+	if len(unsupportedFlags) > 0 {
+		return configuration{}, fmt.Errorf("flags %s aren't supported in "+
+			"new config style, please use -old-config-style or update your configuration",
+			strings.Join(unsupportedFlags, ", "))
+	}
+
+	return cfg, nil
+}
+
+// updateOldConfigFromFlags parses the flags and the config file. Anything which is
+// a zerovalue in the configuration file will be replaced with the flag
+// value, this means that the config file overrides flag values.
+func updateOldConfigFromFlags(cfg oldConfiguration) oldConfiguration {
 	if cfg.PackageName == "" {
 		cfg.PackageName = flagPackageName
 	}
@@ -264,14 +297,63 @@ func configFromFlags() *configuration {
 	if cfg.OutputFile == "" {
 		cfg.OutputFile = flagOutputFile
 	}
+	return cfg
+}
 
-	if cfg.OldAllOfOutput == false {
-		cfg.OldAllOfOutput = flagOldAllOfOutput
+func newConfigFromOldConfig(c oldConfiguration) configuration {
+	// Take flags into account.
+	cfg := updateOldConfigFromFlags(c)
+
+	// Now, copy over field by field, translating flags and old values as
+	// necessary.
+	opts := codegen.Configuration{
+		PackageName: cfg.PackageName,
+	}
+	opts.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix
+
+	for _, g := range cfg.GenerateTargets {
+		switch g {
+		case "client":
+			opts.Generate.Client = true
+		case "chi-server":
+			opts.Generate.ChiServer = true
+		case "server":
+			opts.Generate.EchoServer = true
+		case "gin":
+			opts.Generate.GinServer = true
+		case "gorilla":
+			opts.Generate.GorillaServer = true
+		case "types":
+			opts.Generate.Models = true
+		case "spec":
+			opts.Generate.EmbeddedSpec = true
+		case "skip-fmt":
+			opts.OutputOptions.SkipFmt = true
+		case "skip-prune":
+			opts.OutputOptions.SkipPrune = true
+		default:
+			fmt.Printf("unknown generate option %s\n", g)
+			flag.PrintDefaults()
+			os.Exit(1)
+		}
 	}
 
-	if cfg.OldEnumConflicts == false {
-		cfg.OldEnumConflicts = flagOldEnumConflicts
+	opts.OutputOptions.IncludeTags = cfg.IncludeTags
+	opts.OutputOptions.ExcludeTags = cfg.ExcludeTags
+	opts.OutputOptions.ExcludeSchemas = cfg.ExcludeSchemas
+
+	templates, err := loadTemplateOverrides(cfg.TemplatesDir)
+	if err != nil {
+		errExit("error loading template overrides: %s\n", err)
 	}
+	opts.OutputOptions.UserTemplates = templates
+
+	opts.ImportMapping = cfg.ImportMapping
+
+	opts.Compatibility = cfg.Compatibility
 
-	return &cfg
+	return configuration{
+		Configuration: opts,
+		OutputFile:    cfg.OutputFile,
+	}
 }
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 5a5b006..45bc235 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -46,10 +46,10 @@ type ThingWithID struct {
 }
 
 // AddThingJSONBody defines parameters for AddThing.
-type AddThingJSONBody Thing
+type AddThingJSONBody = Thing
 
 // AddThingJSONRequestBody defines body for AddThing for application/json ContentType.
-type AddThingJSONRequestBody AddThingJSONBody
+type AddThingJSONRequestBody = AddThingJSONBody
 
 // RequestEditorFn  is the function signature for the RequestEditor callback function
 type RequestEditorFn func(ctx context.Context, req *http.Request) error
diff --git a/examples/authenticated-api/echo/api/config.yaml b/examples/authenticated-api/echo/api/config.yaml
index fa4680e..0b176ca 100644
--- a/examples/authenticated-api/echo/api/config.yaml
+++ b/examples/authenticated-api/echo/api/config.yaml
@@ -1,9 +1,9 @@
-output:
-  api.gen.go
 package: api
 generate:
-  - types
-  - client
-  - server
-  - spec
-  - skip-prune
+  echo-server: true
+  client: true
+  models: true
+  embedded-spec: true
+output: api.gen.go
+output-options:
+  skip-prune: true
diff --git a/examples/petstore-expanded/chi/api/cfg.yaml b/examples/petstore-expanded/chi/api/cfg.yaml
new file mode 100644
index 0000000..6d2fa08
--- /dev/null
+++ b/examples/petstore-expanded/chi/api/cfg.yaml
@@ -0,0 +1,6 @@
+package: api
+generate:
+  chi-server: true
+  models: true
+  embedded-spec: true
+output: petstore.gen.go
diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go
index ad1c495..64aec35 100644
--- a/examples/petstore-expanded/chi/api/petstore.gen.go
+++ b/examples/petstore-expanded/chi/api/petstore.gen.go
@@ -58,10 +58,10 @@ type FindPetsParams struct {
 }
 
 // AddPetJSONBody defines parameters for AddPet.
-type AddPetJSONBody NewPet
+type AddPetJSONBody = NewPet
 
 // AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
-type AddPetJSONRequestBody AddPetJSONBody
+type AddPetJSONRequestBody = AddPetJSONBody
 
 // ServerInterface represents all server handlers.
 type ServerInterface interface {
@@ -86,7 +86,7 @@ type ServerInterfaceWrapper struct {
 	ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
 }
 
-type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
+type MiddlewareFunc func(http.Handler) http.Handler
 
 // FindPets operation middleware
 func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
@@ -119,30 +119,30 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.FindPets(w, r, params)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // AddPet operation middleware
 func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.AddPet(w, r)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // DeletePet operation middleware
@@ -154,21 +154,21 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
 	// ------------- Path parameter "id" -------------
 	var id int64
 
-	err = runtime.BindStyledParameter("simple", false, "id", chi.URLParam(r, "id"), &id)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.DeletePet(w, r, id)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // FindPetByID operation middleware
@@ -180,21 +180,21 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
 	// ------------- Path parameter "id" -------------
 	var id int64
 
-	err = runtime.BindStyledParameter("simple", false, "id", chi.URLParam(r, "id"), &id)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.FindPetByID(w, r, id)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 type UnescapedCookieParamError struct {
diff --git a/examples/petstore-expanded/chi/api/petstore.go b/examples/petstore-expanded/chi/api/petstore.go
index a24e1f2..ea8c34a 100644
--- a/examples/petstore-expanded/chi/api/petstore.go
+++ b/examples/petstore-expanded/chi/api/petstore.go
@@ -1,4 +1,4 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=api --generate types,chi-server,spec -o petstore.gen.go ../../petstore-expanded.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
 
 package api
 
diff --git a/examples/petstore-expanded/echo/api/petstore-types.gen.go b/examples/petstore-expanded/echo/api/petstore-types.gen.go
index d3d4d8a..67ee510 100644
--- a/examples/petstore-expanded/echo/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/echo/api/petstore-types.gen.go
@@ -43,7 +43,7 @@ type FindPetsParams struct {
 }
 
 // AddPetJSONBody defines parameters for AddPet.
-type AddPetJSONBody NewPet
+type AddPetJSONBody = NewPet
 
 // AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
-type AddPetJSONRequestBody AddPetJSONBody
+type AddPetJSONRequestBody = AddPetJSONBody
diff --git a/examples/petstore-expanded/echo/api/server.cfg.yaml b/examples/petstore-expanded/echo/api/server.cfg.yaml
index 653a7c5..4c16329 100644
--- a/examples/petstore-expanded/echo/api/server.cfg.yaml
+++ b/examples/petstore-expanded/echo/api/server.cfg.yaml
@@ -1,6 +1,5 @@
-output:
-  petstore-server.gen.go
-generate:
-  - server
-  - spec
 package: api
+generate:
+  echo-server: true
+  embedded-spec: true
+output: petstore-server.gen.go
diff --git a/examples/petstore-expanded/echo/api/types.cfg.yaml b/examples/petstore-expanded/echo/api/types.cfg.yaml
index e812b1a..9ac30e1 100644
--- a/examples/petstore-expanded/echo/api/types.cfg.yaml
+++ b/examples/petstore-expanded/echo/api/types.cfg.yaml
@@ -1,5 +1,4 @@
-output:
-  petstore-types.gen.go
-generate:
-  - types
 package: api
+generate:
+  models: true
+output: petstore-types.gen.go
diff --git a/examples/petstore-expanded/gin/api/petstore-types.gen.go b/examples/petstore-expanded/gin/api/petstore-types.gen.go
index d3d4d8a..67ee510 100644
--- a/examples/petstore-expanded/gin/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-types.gen.go
@@ -43,7 +43,7 @@ type FindPetsParams struct {
 }
 
 // AddPetJSONBody defines parameters for AddPet.
-type AddPetJSONBody NewPet
+type AddPetJSONBody = NewPet
 
 // AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
-type AddPetJSONRequestBody AddPetJSONBody
+type AddPetJSONRequestBody = AddPetJSONBody
diff --git a/examples/petstore-expanded/gin/api/server.cfg.yaml b/examples/petstore-expanded/gin/api/server.cfg.yaml
index 2e9b506..61944bc 100644
--- a/examples/petstore-expanded/gin/api/server.cfg.yaml
+++ b/examples/petstore-expanded/gin/api/server.cfg.yaml
@@ -1,5 +1,5 @@
-output: petstore-server.gen.go
-generate:
-  - gin
-  - spec
 package: api
+generate:
+  gin-server: true
+  embedded-spec: true
+output: petstore-server.gen.go
diff --git a/examples/petstore-expanded/gin/api/types.cfg.yaml b/examples/petstore-expanded/gin/api/types.cfg.yaml
index ad72dc3..9ac30e1 100644
--- a/examples/petstore-expanded/gin/api/types.cfg.yaml
+++ b/examples/petstore-expanded/gin/api/types.cfg.yaml
@@ -1,4 +1,4 @@
-output: petstore-types.gen.go
-generate:
-  - types
 package: api
+generate:
+  models: true
+output: petstore-types.gen.go
diff --git a/examples/petstore-expanded/gorilla/api/cfg.yaml b/examples/petstore-expanded/gorilla/api/cfg.yaml
new file mode 100644
index 0000000..7f1a2d7
--- /dev/null
+++ b/examples/petstore-expanded/gorilla/api/cfg.yaml
@@ -0,0 +1,6 @@
+package: api
+generate:
+  gorilla-server: true
+  models: true
+  embedded-spec: true
+output: petstore.gen.go
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
new file mode 100644
index 0000000..5ddb9e1
--- /dev/null
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -0,0 +1,427 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
+package api
+
+import (
+	"bytes"
+	"compress/gzip"
+	"encoding/base64"
+	"fmt"
+	"net/http"
+	"net/url"
+	"path"
+	"strings"
+
+	"github.com/deepmap/oapi-codegen/pkg/runtime"
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gorilla/mux"
+)
+
+// Error defines model for Error.
+type Error struct {
+	// Error code
+	Code int32 `json:"code"`
+
+	// Error message
+	Message string `json:"message"`
+}
+
+// NewPet defines model for NewPet.
+type NewPet struct {
+	// Name of the pet
+	Name string `json:"name"`
+
+	// Type of the pet
+	Tag *string `json:"tag,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+	// Unique id of the pet
+	Id int64 `json:"id"`
+
+	// Name of the pet
+	Name string `json:"name"`
+
+	// Type of the pet
+	Tag *string `json:"tag,omitempty"`
+}
+
+// FindPetsParams defines parameters for FindPets.
+type FindPetsParams struct {
+	// tags to filter by
+	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+
+	// maximum number of results to return
+	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
+}
+
+// AddPetJSONBody defines parameters for AddPet.
+type AddPetJSONBody = NewPet
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = AddPetJSONBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+	// Returns all pets
+	// (GET /pets)
+	FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
+	// Creates a new pet
+	// (POST /pets)
+	AddPet(w http.ResponseWriter, r *http.Request)
+	// Deletes a pet by ID
+	// (DELETE /pets/{id})
+	DeletePet(w http.ResponseWriter, r *http.Request, id int64)
+	// Returns a pet by ID
+	// (GET /pets/{id})
+	FindPetByID(w http.ResponseWriter, r *http.Request, id int64)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+	Handler            ServerInterface
+	HandlerMiddlewares []MiddlewareFunc
+	ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
+
+// FindPets operation middleware
+func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+
+	var err error
+
+	// Parameter object where we will unmarshal all parameters from the context
+	var params FindPetsParams
+
+	// ------------- Optional query parameter "tags" -------------
+	if paramValue := r.URL.Query().Get("tags"); paramValue != "" {
+
+	}
+
+	err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), &params.Tags)
+	if err != nil {
+		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+		return
+	}
+
+	// ------------- Optional query parameter "limit" -------------
+	if paramValue := r.URL.Query().Get("limit"); paramValue != "" {
+
+	}
+
+	err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), &params.Limit)
+	if err != nil {
+		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+		return
+	}
+
+	var handler = func(w http.ResponseWriter, r *http.Request) {
+		siw.Handler.FindPets(w, r, params)
+	}
+
+	for _, middleware := range siw.HandlerMiddlewares {
+		handler = middleware(handler)
+	}
+
+	handler(w, r.WithContext(ctx))
+}
+
+// AddPet operation middleware
+func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+
+	var handler = func(w http.ResponseWriter, r *http.Request) {
+		siw.Handler.AddPet(w, r)
+	}
+
+	for _, middleware := range siw.HandlerMiddlewares {
+		handler = middleware(handler)
+	}
+
+	handler(w, r.WithContext(ctx))
+}
+
+// DeletePet operation middleware
+func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+
+	var err error
+
+	// ------------- Path parameter "id" -------------
+	var id int64
+
+	err = runtime.BindStyledParameter("simple", false, "id", mux.Vars(r)["id"], &id)
+	if err != nil {
+		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+		return
+	}
+
+	var handler = func(w http.ResponseWriter, r *http.Request) {
+		siw.Handler.DeletePet(w, r, id)
+	}
+
+	for _, middleware := range siw.HandlerMiddlewares {
+		handler = middleware(handler)
+	}
+
+	handler(w, r.WithContext(ctx))
+}
+
+// FindPetByID operation middleware
+func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+
+	var err error
+
+	// ------------- Path parameter "id" -------------
+	var id int64
+
+	err = runtime.BindStyledParameter("simple", false, "id", mux.Vars(r)["id"], &id)
+	if err != nil {
+		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+		return
+	}
+
+	var handler = func(w http.ResponseWriter, r *http.Request) {
+		siw.Handler.FindPetByID(w, r, id)
+	}
+
+	for _, middleware := range siw.HandlerMiddlewares {
+		handler = middleware(handler)
+	}
+
+	handler(w, r.WithContext(ctx))
+}
+
+type UnescapedCookieParamError struct {
+	ParamName string
+	Err       error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+	return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+	return e.Err
+}
+
+type UnmarshalingParamError struct {
+	ParamName string
+	Err       error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+	return e.Err
+}
+
+type RequiredParamError struct {
+	ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+	return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+	ParamName string
+	Err       error
+}
+
+func (e *RequiredHeaderError) Error() string {
+	return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+	return e.Err
+}
+
+type InvalidParamFormatError struct {
+	ParamName string
+	Err       error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+	return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+	return e.Err
+}
+
+type TooManyValuesForParamError struct {
+	ParamName string
+	Count     int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+	return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+	return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+	BaseURL          string
+	BaseRouter       *mux.Router
+	Middlewares      []MiddlewareFunc
+	ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+	return HandlerWithOptions(si, GorillaServerOptions{
+		BaseRouter: r,
+	})
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+	return HandlerWithOptions(si, GorillaServerOptions{
+		BaseURL:    baseURL,
+		BaseRouter: r,
+	})
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+	r := options.BaseRouter
+
+	if r == nil {
+		r = mux.NewRouter()
+	}
+	if options.ErrorHandlerFunc == nil {
+		options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+		}
+	}
+	wrapper := ServerInterfaceWrapper{
+		Handler:            si,
+		HandlerMiddlewares: options.Middlewares,
+		ErrorHandlerFunc:   options.ErrorHandlerFunc,
+	}
+
+	r.HandleFunc(options.BaseURL+"/pets", wrapper.FindPets).Methods("GET")
+
+	r.HandleFunc(options.BaseURL+"/pets", wrapper.AddPet).Methods("POST")
+
+	r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.DeletePet).Methods("DELETE")
+
+	r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.FindPetByID).Methods("GET")
+
+	return r
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+	"H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
+	"I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
+	"od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
+	"9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
+	"MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
+	"czTdRLH53K7Bu7sF/EToTWdK0qC1yDifzU5idt2LJN5BRj86qsGyRoGSKQNqMlliIsAMGIC+tmUSYSAf",
+	"Q5aEQrAklJIoA4dKwaeRgj7pbX8DeSTLS7ZYt+qMY0sh09Eb5t2Idk3wpr85g5zns9nT01OP9XYf02o2",
+	"xebZnxbvP3z8/OF3b/qbfi3eVcNQ8vnT8jOlDVu6lvesLpmpGCzulLO7KU3TmQ2l3Ej5fX/T3+iT40gB",
+	"RzZz87Ze6syIsq6OmClB+mPVDHZO619ISgoZ0LnKJCxT9JWhvM1CvlGt/0umBGsl2VrKGSR+CR/RQ6YB",
+	"bAwDewpSPFCWHn5EshQwg5AfY4KMKxbhDBlHptBBIAtpHYMtGTL5kwUsgJ6kh3cUCAOgwCrhhgcELKtC",
+	"HaAFRlsc19Ae3peEDywlQRw4gouJfAcxBUwEtCIBcjShC2Q7sCXlkrUgHFkpuYfbwhk8g5Q0cu5gLG7D",
+	"AZPuRSlq0h0IB8tDCQIbTFwy/FqyxB4WAdZoYa0gMGeC0aEQwsBWilc6Fq2kNBcceORsOawAg2g2x9wd",
+	"r4rDQ+bjGhNJwj2Juh58dJSFCdiPlAZWpv7KG/QtIXT8WNDDwKjMJMzwqLltyLFAiAEkJolJKeElheGw",
+	"ew93CSlTEIVJgf0RQEkBYRNdkREFNhQooAJu5OqHx5L0GYtwfPKS0sT6Ei07zmeb1B30ozvqayHHAR2p",
+	"sEOnPFpKKJqYfvfwueSRwsDKskM1zxBdTJ06MJMVdXPNslpFs+5gQ2u2xSFoY0tD8eD4gVLs4ceYHhio",
+	"cPZxOJVBb1djO7QcGPsv4Uv4TENVomRYkprPxYeYagDFo2NSkVR8D1obHusDJ/I5uw6onFVLkxxcUR+q",
+	"O3u4W2Mm51phjJSm8EpzlZcEllgsP5RGOO730XWn8Rtyk3S8oZSwO99a6wR46A6FGPhh3cPPAiM5R0Eo",
+	"67kxxlxIK2lfRD0oFbivAi26PZf7J+3Tqkx2FcjBFqEEC5I4Sz2WNixIPfxQsiUgqd1gKHyoAu0U2ZKj",
+	"xBVO8+8+wKtbClbz2OIzBvC40pTJTWr18OfSQn10qltTj0rzzhFKd2g+gMVqkbSVkz1b2pM5piZzqEY1",
+	"iwoMHLojlKlwA2feA86KwbKUgRVqzghF9j6bhGw7nZFW9+vh7lSYytyEcUwkXPxJ52qmKd2Jv7X19l/0",
+	"iNORoR53i8HMzQ8cBj1f6rGRlABKuc4g54eF4Er7PizZCSV42BodBczcPBZK2+M5r+tMN42MdSoR8vUM",
+	"upyh2gVMCbf6P8u2Hns6nNTx5hyBx6/stY0X/0BJ55lEuTipsFI9y76BybFnOQP1m8Po7l4HoDxqa6no",
+	"39zc7KceCm1aG0c3DQ6zX7NCfL6W9mujXJvjXhCxu5h/RhLYg2nT0RKLk38Iz2sw2lB/ZeMS6OuorVV7",
+	"cFvTmVy8x7S9MkAotjHmK6PG+0QodWQL9KRr97NYnWv0DG7YdYmOc87FJxouzPpuUK+aNptSlu/jsP2X",
+	"sbCfqy9puCNRj+Ew6NcBtjmdkSUV2v2TnvlNq/z3WONC8Hq/zqOzZx52zSKO5MrrV7uusZnDytV3FnhA",
+	"bbOxuWZxC7loTlc8clujm01e7WiLW+0hY9N2wjL1Dx2gj+2Dhwulv9VLrr9LXfaS7y6zViANxfCfJOTt",
+	"QYyqwhYWtwrv9ReKc8UOOi5uv3X8fL+t9/5+vZYkdv1vk+t/toxfKNrUr0sobfYynb3H71/J+5MXW307",
+	"3d3v/hYAAP//wO3O5VcSAAA=",
+}
+
+// GetSwagger returns the content of the embedded swagger specification file
+// or error if failed to decode
+func decodeSpec() ([]byte, error) {
+	zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+	if err != nil {
+		return nil, fmt.Errorf("error base64 decoding spec: %s", err)
+	}
+	zr, err := gzip.NewReader(bytes.NewReader(zipped))
+	if err != nil {
+		return nil, fmt.Errorf("error decompressing spec: %s", err)
+	}
+	var buf bytes.Buffer
+	_, err = buf.ReadFrom(zr)
+	if err != nil {
+		return nil, fmt.Errorf("error decompressing spec: %s", err)
+	}
+
+	return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cached of a decoded swagger spec
+func decodeSpecCached() func() ([]byte, error) {
+	data, err := decodeSpec()
+	return func() ([]byte, error) {
+		return data, err
+	}
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+	var res = make(map[string]func() ([]byte, error))
+	if len(pathToFile) > 0 {
+		res[pathToFile] = rawSpec
+	}
+
+	return res
+}
+
+// GetSwagger returns the Swagger specification corresponding to the generated code
+// in this file. The external references of Swagger specification are resolved.
+// The logic of resolving external references is tightly connected to "import-mapping" feature.
+// Externally referenced files must be embedded in the corresponding golang packages.
+// Urls can be supported but this task was out of the scope.
+func GetSwagger() (swagger *openapi3.T, err error) {
+	var resolvePath = PathToRawSpec("")
+
+	loader := openapi3.NewLoader()
+	loader.IsExternalRefsAllowed = true
+	loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+		var pathToFile = url.String()
+		pathToFile = path.Clean(pathToFile)
+		getSpec, ok := resolvePath[pathToFile]
+		if !ok {
+			err1 := fmt.Errorf("path not found: %s", pathToFile)
+			return nil, err1
+		}
+		return getSpec()
+	}
+	var specData []byte
+	specData, err = rawSpec()
+	if err != nil {
+		return
+	}
+	swagger, err = loader.LoadFromData(specData)
+	if err != nil {
+		return
+	}
+	return
+}
diff --git a/examples/petstore-expanded/gorilla/api/petstore.go b/examples/petstore-expanded/gorilla/api/petstore.go
new file mode 100644
index 0000000..ea8c34a
--- /dev/null
+++ b/examples/petstore-expanded/gorilla/api/petstore.go
@@ -0,0 +1,128 @@
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
+
+package api
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"sync"
+)
+
+type PetStore struct {
+	Pets   map[int64]Pet
+	NextId int64
+	Lock   sync.Mutex
+}
+
+// Make sure we conform to ServerInterface
+
+var _ ServerInterface = (*PetStore)(nil)
+
+func NewPetStore() *PetStore {
+	return &PetStore{
+		Pets:   make(map[int64]Pet),
+		NextId: 1000,
+	}
+}
+
+// This function wraps sending of an error in the Error format, and
+// handling the failure to marshal that.
+func sendPetstoreError(w http.ResponseWriter, code int, message string) {
+	petErr := Error{
+		Code:    int32(code),
+		Message: message,
+	}
+	w.WriteHeader(code)
+	json.NewEncoder(w).Encode(petErr)
+}
+
+// Here, we implement all of the handlers in the ServerInterface
+func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	var result []Pet
+
+	for _, pet := range p.Pets {
+		if params.Tags != nil {
+			// If we have tags,  filter pets by tag
+			for _, t := range *params.Tags {
+				if pet.Tag != nil && (*pet.Tag == t) {
+					result = append(result, pet)
+				}
+			}
+		} else {
+			// Add all pets if we're not filtering
+			result = append(result, pet)
+		}
+
+		if params.Limit != nil {
+			l := int(*params.Limit)
+			if len(result) >= l {
+				// We're at the limit
+				break
+			}
+		}
+	}
+
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(result)
+}
+
+func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) {
+	// We expect a NewPet object in the request body.
+	var newPet NewPet
+	if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil {
+		sendPetstoreError(w, http.StatusBadRequest, "Invalid format for NewPet")
+		return
+	}
+
+	// We now have a pet, let's add it to our "database".
+
+	// We're always asynchronous, so lock unsafe operations below
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	// We handle pets, not NewPets, which have an additional ID field
+	var pet Pet
+	pet.Name = newPet.Name
+	pet.Tag = newPet.Tag
+	pet.Id = p.NextId
+	p.NextId = p.NextId + 1
+
+	// Insert into map
+	p.Pets[pet.Id] = pet
+
+	// Now, we have to return the NewPet
+	w.WriteHeader(http.StatusCreated)
+	json.NewEncoder(w).Encode(pet)
+}
+
+func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) {
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	pet, found := p.Pets[id]
+	if !found {
+		sendPetstoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(pet)
+}
+
+func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) {
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	_, found := p.Pets[id]
+	if !found {
+		sendPetstoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+		return
+	}
+	delete(p.Pets, id)
+
+	w.WriteHeader(http.StatusNoContent)
+}
diff --git a/examples/petstore-expanded/gorilla/petstore.go b/examples/petstore-expanded/gorilla/petstore.go
new file mode 100644
index 0000000..b31239b
--- /dev/null
+++ b/examples/petstore-expanded/gorilla/petstore.go
@@ -0,0 +1,53 @@
+// This is an example of implementing the Pet Store from the OpenAPI documentation
+// found at:
+// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+
+	api "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gorilla/api"
+	middleware "github.com/deepmap/oapi-codegen/pkg/chi-middleware"
+	"github.com/gorilla/mux"
+)
+
+func main() {
+	var port = flag.Int("port", 8080, "Port for test HTTP server")
+	flag.Parse()
+
+	swagger, err := api.GetSwagger()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
+		os.Exit(1)
+	}
+
+	// Clear out the servers array in the swagger spec, that skips validating
+	// that server names match. We don't know how this thing will be run.
+	swagger.Servers = nil
+
+	// Create an instance of our handler which satisfies the generated interface
+	petStore := api.NewPetStore()
+
+	// This is how you set up a basic Gorilla router
+	r := mux.NewRouter()
+
+	// Use our validation middleware to check all requests against the
+	// OpenAPI schema.
+	r.Use(middleware.OapiRequestValidator(swagger))
+
+	// We now register our petStore above as the handler for the interface
+	api.HandlerFromMux(petStore, r)
+
+	s := &http.Server{
+		Handler: r,
+		Addr:    fmt.Sprintf("0.0.0.0:%d", *port),
+	}
+
+	// And we serve HTTP until the world ends.
+	log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/petstore-expanded/internal/doc.go b/examples/petstore-expanded/internal/doc.go
index ac961b7..db05a3a 100644
--- a/examples/petstore-expanded/internal/doc.go
+++ b/examples/petstore-expanded/internal/doc.go
@@ -17,4 +17,4 @@ package internal
 // server. The file petstore.gen.go is automatically generated from the schema
 
 // Run oapi-codegen to regenerate the petstore boilerplate
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=petstore --generate types,client -o ../petstore-client.gen.go ../petstore-expanded.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=petstore --generate types,client -o ../petstore-client.gen.go ../petstore-expanded.yaml
diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index ab0fa90..6a73e9b 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -57,10 +57,10 @@ type FindPetsParams struct {
 }
 
 // AddPetJSONBody defines parameters for AddPet.
-type AddPetJSONBody NewPet
+type AddPetJSONBody = NewPet
 
 // AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
-type AddPetJSONRequestBody AddPetJSONBody
+type AddPetJSONRequestBody = AddPetJSONBody
 
 // RequestEditorFn  is the function signature for the RequestEditor callback function
 type RequestEditorFn func(ctx context.Context, req *http.Request) error
diff --git a/go.mod b/go.mod
index 7d46fee..6e2b42b 100644
--- a/go.mod
+++ b/go.mod
@@ -11,6 +11,7 @@ require (
 	github.com/golang/protobuf v1.5.2 // indirect
 	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/json-iterator/go v1.1.12 // indirect
 	github.com/labstack/echo/v4 v4.7.2
 	github.com/lestrrat-go/blackmagic v1.0.1 // indirect
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index 2dd5367..ed43e2d 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -33,31 +33,13 @@ import (
 //go:embed templates
 var templates embed.FS
 
-// Options defines the optional code to generate.
-type Options struct {
-	GenerateChiServer  bool              // GenerateChiServer specifies whether to generate chi server boilerplate
-	GenerateEchoServer bool              // GenerateEchoServer specifies whether to generate echo server boilerplate
-	GenerateGinServer  bool              // GenerateGinServer specifies whether to generate echo server boilerplate
-	GenerateClient     bool              // GenerateClient specifies whether to generate client boilerplate
-	GenerateTypes      bool              // GenerateTypes specifies whether to generate type definitions
-	EmbedSpec          bool              // Whether to embed the swagger spec in the generated code
-	SkipFmt            bool              // Whether to skip go imports on the generated code
-	SkipPrune          bool              // Whether to skip pruning unused components on the generated code
-	AliasTypes         bool              // Whether to alias types if possible
-	IncludeTags        []string          // Only include operations that have one of these tags. Ignored when empty.
-	ExcludeTags        []string          // Exclude operations that have one of these tags. Ignored when empty.
-	UserTemplates      map[string]string // Override built-in templates from user-provided files
-	ImportMapping      map[string]string // ImportMapping specifies the golang package path for each external reference
-	ExcludeSchemas     []string          // Exclude from generation schemas with given names. Ignored when empty.
-	OldMergeSchemas    bool              // Schema merging for allOf was changed in a big way, when true, the old way is used
-	OldEnumConflicts   bool              // When set to true, we include the object path in enum names, otherwise, rely on global de-dup
-	ResponseTypeSuffix string            // The suffix used for responses types
+// globalState stores all global state. Please don't put global state anywhere
+// else so that we can easily track it.
+var globalState struct {
+	options Configuration
+	spec    *openapi3.T
 }
 
-// We store options globally to simplify accessing them from all the codegen
-// functions.
-var options Options
-
 // goImport represents a go package to be imported in the generated code
 type goImport struct {
 	Name string // package name
@@ -114,24 +96,25 @@ func constructImportMapping(importMapping map[string]string) importMap {
 // Generate uses the Go templating engine to generate all of our server wrappers from
 // the descriptions we've built up above from the schema objects.
 // opts defines
-func Generate(swagger *openapi3.T, packageName string, opts Options) (string, error) {
+func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 	// This is global state
-	options = opts
+	globalState.options = opts
+	globalState.spec = spec
 
 	importMapping = constructImportMapping(opts.ImportMapping)
 
-	filterOperationsByTag(swagger, opts)
-	if !opts.SkipPrune {
-		pruneUnusedComponents(swagger)
+	filterOperationsByTag(spec, opts)
+	if !opts.OutputOptions.SkipPrune {
+		pruneUnusedComponents(spec)
 	}
 
 	// if we are provided an override for the response type suffix update it
-	if opts.ResponseTypeSuffix != "" {
-		responseTypeSuffix = opts.ResponseTypeSuffix
+	if opts.OutputOptions.ResponseTypeSuffix != "" {
+		responseTypeSuffix = opts.OutputOptions.ResponseTypeSuffix
 	}
 
 	// This creates the golang templates text package
-	TemplateFunctions["opts"] = func() Options { return options }
+	TemplateFunctions["opts"] = func() Configuration { return globalState.options }
 	t := template.New("oapi-codegen").Funcs(TemplateFunctions)
 	// This parses all of our own template files into the template object
 	// above
@@ -142,22 +125,22 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 
 	// Override built-in templates with user-provided versions
 	for _, tpl := range t.Templates() {
-		if _, ok := opts.UserTemplates[tpl.Name()]; ok {
+		if _, ok := opts.OutputOptions.UserTemplates[tpl.Name()]; ok {
 			utpl := t.New(tpl.Name())
-			if _, err := utpl.Parse(opts.UserTemplates[tpl.Name()]); err != nil {
+			if _, err := utpl.Parse(opts.OutputOptions.UserTemplates[tpl.Name()]); err != nil {
 				return "", fmt.Errorf("error parsing user-provided template %q: %w", tpl.Name(), err)
 			}
 		}
 	}
 
-	ops, err := OperationDefinitions(swagger)
+	ops, err := OperationDefinitions(spec)
 	if err != nil {
 		return "", fmt.Errorf("error creating operation definitions: %w", err)
 	}
 
 	var typeDefinitions, constantDefinitions string
-	if opts.GenerateTypes {
-		typeDefinitions, err = GenerateTypeDefinitions(t, swagger, ops, opts.ExcludeSchemas)
+	if opts.Generate.Models {
+		typeDefinitions, err = GenerateTypeDefinitions(t, spec, ops, opts.OutputOptions.ExcludeSchemas)
 		if err != nil {
 			return "", fmt.Errorf("error generating type definitions: %w", err)
 		}
@@ -170,7 +153,7 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	}
 
 	var echoServerOut string
-	if opts.GenerateEchoServer {
+	if opts.Generate.EchoServer {
 		echoServerOut, err = GenerateEchoServer(t, ops)
 		if err != nil {
 			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
@@ -178,7 +161,7 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	}
 
 	var chiServerOut string
-	if opts.GenerateChiServer {
+	if opts.Generate.ChiServer {
 		chiServerOut, err = GenerateChiServer(t, ops)
 		if err != nil {
 			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
@@ -186,15 +169,23 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	}
 
 	var ginServerOut string
-	if opts.GenerateGinServer {
+	if opts.Generate.GinServer {
 		ginServerOut, err = GenerateGinServer(t, ops)
 		if err != nil {
 			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
 		}
 	}
 
+	var gorillaServerOut string
+	if opts.Generate.GorillaServer {
+		gorillaServerOut, err = GenerateGorillaServer(t, ops)
+		if err != nil {
+			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
+		}
+	}
+
 	var clientOut string
-	if opts.GenerateClient {
+	if opts.Generate.Client {
 		clientOut, err = GenerateClient(t, ops)
 		if err != nil {
 			return "", fmt.Errorf("error generating client: %w", err)
@@ -202,7 +193,7 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	}
 
 	var clientWithResponsesOut string
-	if opts.GenerateClient {
+	if opts.Generate.Client {
 		clientWithResponsesOut, err = GenerateClientWithResponses(t, ops)
 		if err != nil {
 			return "", fmt.Errorf("error generating client with responses: %w", err)
@@ -210,8 +201,8 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	}
 
 	var inlinedSpec string
-	if opts.EmbedSpec {
-		inlinedSpec, err = GenerateInlinedSpec(t, importMapping, swagger)
+	if opts.Generate.EmbeddedSpec {
+		inlinedSpec, err = GenerateInlinedSpec(t, importMapping, spec)
 		if err != nil {
 			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
 		}
@@ -221,7 +212,7 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 	w := bufio.NewWriter(&buf)
 
 	externalImports := importMapping.GoImports()
-	importsOut, err := GenerateImports(t, externalImports, packageName)
+	importsOut, err := GenerateImports(t, externalImports, opts.PackageName)
 	if err != nil {
 		return "", fmt.Errorf("error generating imports: %w", err)
 	}
@@ -241,7 +232,7 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 		return "", fmt.Errorf("error writing type definitions: %w", err)
 	}
 
-	if opts.GenerateClient {
+	if opts.Generate.Client {
 		_, err = w.WriteString(clientOut)
 		if err != nil {
 			return "", fmt.Errorf("error writing client: %w", err)
@@ -252,28 +243,35 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 		}
 	}
 
-	if opts.GenerateEchoServer {
+	if opts.Generate.EchoServer {
 		_, err = w.WriteString(echoServerOut)
 		if err != nil {
 			return "", fmt.Errorf("error writing server path handlers: %w", err)
 		}
 	}
 
-	if opts.GenerateChiServer {
+	if opts.Generate.ChiServer {
 		_, err = w.WriteString(chiServerOut)
 		if err != nil {
 			return "", fmt.Errorf("error writing server path handlers: %w", err)
 		}
 	}
 
-	if opts.GenerateGinServer {
+	if opts.Generate.GinServer {
 		_, err = w.WriteString(ginServerOut)
 		if err != nil {
 			return "", fmt.Errorf("error writing server path handlers: %w", err)
 		}
 	}
 
-	if opts.EmbedSpec {
+	if opts.Generate.GorillaServer {
+		_, err = w.WriteString(gorillaServerOut)
+		if err != nil {
+			return "", fmt.Errorf("error writing server path handlers: %w", err)
+		}
+	}
+
+	if opts.Generate.EmbeddedSpec {
 		_, err = w.WriteString(inlinedSpec)
 		if err != nil {
 			return "", fmt.Errorf("error writing inlined spec: %w", err)
@@ -290,11 +288,11 @@ func Generate(swagger *openapi3.T, packageName string, opts Options) (string, er
 
 	// The generation code produces unindented horrors. Use the Go Imports
 	// to make it all pretty.
-	if opts.SkipFmt {
+	if opts.OutputOptions.SkipFmt {
 		return goCode, nil
 	}
 
-	outBytes, err := imports.Process(packageName+".go", []byte(goCode), nil)
+	outBytes, err := imports.Process(opts.PackageName+".go", []byte(goCode), nil)
 	if err != nil {
 		fmt.Println(goCode)
 		return "", fmt.Errorf("error formatting Go code: %w", err)
@@ -376,7 +374,7 @@ func GenerateConstants(t *template.Template, ops []OperationDefinition) (string,
 	return GenerateTemplates([]string{"constants.tmpl"}, t, constants)
 }
 
-// Generates type definitions for any custom types defined in the
+// GenerateTypesForSchemas generates type definitions for any custom types defined in the
 // components/schemas section of the Swagger spec.
 func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) ([]TypeDefinition, error) {
 	excludeSchemasMap := make(map[string]bool)
@@ -396,9 +394,14 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.
 			return nil, fmt.Errorf("error converting Schema %s to Go type: %w", schemaName, err)
 		}
 
+		goTypeName, err := renameSchema(schemaName, schemaRef)
+		if err != nil {
+			return nil, fmt.Errorf("error making name for components/schemas/%s: %w", schemaName, err)
+		}
+
 		types = append(types, TypeDefinition{
 			JsonName: schemaName,
-			TypeName: SchemaNameToTypeName(schemaName),
+			TypeName: goTypeName,
 			Schema:   goSchema,
 		})
 
@@ -407,7 +410,7 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.
 	return types, nil
 }
 
-// Generates type definitions for any custom types defined in the
+// GenerateTypesForParameters generates type definitions for any custom types defined in the
 // components/parameters section of the Swagger spec.
 func GenerateTypesForParameters(t *template.Template, params map[string]*openapi3.ParameterRef) ([]TypeDefinition, error) {
 	var types []TypeDefinition
@@ -419,10 +422,15 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi
 			return nil, fmt.Errorf("error generating Go type for schema in parameter %s: %w", paramName, err)
 		}
 
+		goTypeName, err := renameParameter(paramName, paramOrRef)
+		if err != nil {
+			return nil, fmt.Errorf("error making name for components/parameters/%s: %w", paramName, err)
+		}
+
 		typeDef := TypeDefinition{
 			JsonName: paramName,
 			Schema:   goType,
-			TypeName: SchemaNameToTypeName(paramName),
+			TypeName: goTypeName,
 		}
 
 		if paramOrRef.Ref != "" {
@@ -439,7 +447,7 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi
 	return types, nil
 }
 
-// Generates type definitions for any custom types defined in the
+// GenerateTypesForResponses generates type definitions for any custom types defined in the
 // components/responses section of the Swagger spec.
 func GenerateTypesForResponses(t *template.Template, responses openapi3.Responses) ([]TypeDefinition, error) {
 	var types []TypeDefinition
@@ -458,10 +466,15 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
 				return nil, fmt.Errorf("error generating Go type for schema in response %s: %w", responseName, err)
 			}
 
+			goTypeName, err := renameResponse(responseName, responseOrRef)
+			if err != nil {
+				return nil, fmt.Errorf("error making name for components/responses/%s: %w", responseName, err)
+			}
+
 			typeDef := TypeDefinition{
 				JsonName: responseName,
 				Schema:   goType,
-				TypeName: SchemaNameToTypeName(responseName),
+				TypeName: goTypeName,
 			}
 
 			if responseOrRef.Ref != "" {
@@ -478,35 +491,40 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
 	return types, nil
 }
 
-// Generates type definitions for any custom types defined in the
+// GenerateTypesForRequestBodies generates type definitions for any custom types defined in the
 // components/requestBodies section of the Swagger spec.
 func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*openapi3.RequestBodyRef) ([]TypeDefinition, error) {
 	var types []TypeDefinition
 
-	for _, bodyName := range SortedRequestBodyKeys(bodies) {
-		bodyOrRef := bodies[bodyName]
+	for _, requestBodyName := range SortedRequestBodyKeys(bodies) {
+		requestBodyRef := bodies[requestBodyName]
 
 		// As for responses, we will only generate Go code for JSON bodies,
 		// the other body formats are up to the user.
-		response := bodyOrRef.Value
+		response := requestBodyRef.Value
 		jsonBody, found := response.Content["application/json"]
 		if found {
-			goType, err := GenerateGoSchema(jsonBody.Schema, []string{bodyName})
+			goType, err := GenerateGoSchema(jsonBody.Schema, []string{requestBodyName})
+			if err != nil {
+				return nil, fmt.Errorf("error generating Go type for schema in body %s: %w", requestBodyName, err)
+			}
+
+			goTypeName, err := renameRequestBody(requestBodyName, requestBodyRef)
 			if err != nil {
-				return nil, fmt.Errorf("error generating Go type for schema in body %s: %w", bodyName, err)
+				return nil, fmt.Errorf("error making name for components/schemas/%s: %w", requestBodyName, err)
 			}
 
 			typeDef := TypeDefinition{
-				JsonName: bodyName,
+				JsonName: requestBodyName,
 				Schema:   goType,
-				TypeName: SchemaNameToTypeName(bodyName),
+				TypeName: goTypeName,
 			}
 
-			if bodyOrRef.Ref != "" {
+			if requestBodyRef.Ref != "" {
 				// Generate a reference type for referenced bodies
-				refType, err := RefPathToGoType(bodyOrRef.Ref)
+				refType, err := RefPathToGoType(requestBodyRef.Ref)
 				if err != nil {
-					return nil, fmt.Errorf("error generating Go type for (%s) in body %s: %w", bodyOrRef.Ref, bodyName, err)
+					return nil, fmt.Errorf("error generating Go type for (%s) in body %s: %w", requestBodyRef.Ref, requestBodyName, err)
 				}
 				typeDef.TypeName = SchemaNameToTypeName(refType)
 			}
@@ -516,7 +534,7 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open
 	return types, nil
 }
 
-// Helper function to pass a bunch of types to the template engine, and buffer
+// GenerateTypes passes a bunch of types to the template engine, and buffers
 // its output into a string.
 func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) {
 	m := map[string]bool{}
@@ -604,7 +622,7 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
 
 		// Another edge case is that an enum value can conflict with its own
 		// type name.
-		_, found := e1.GetValues()[e1.TypeName];
+		_, found := e1.GetValues()[e1.TypeName]
 		if found {
 			e1.Conflicts = true
 			enums[i] = e1
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
new file mode 100644
index 0000000..5dd98eb
--- /dev/null
+++ b/pkg/codegen/configuration.go
@@ -0,0 +1,97 @@
+package codegen
+
+import (
+	"errors"
+	"reflect"
+)
+
+// Configuration defines code generation customizations
+type Configuration struct {
+	PackageName   string               `yaml:"package"` // PackageName to generate
+	Generate      GenerateOptions      `yaml:"generate,omitempty"`
+	Compatibility CompatibilityOptions `yaml:"compatibility,omitempty"`
+	OutputOptions OutputOptions        `yaml:"output-options,omitempty"`
+	ImportMapping map[string]string    `yaml:"import-mapping,omitempty"` // ImportMapping specifies the golang package path for each external reference
+}
+
+// GenerateOptions specifies which supported output formats to generate.
+type GenerateOptions struct {
+	ChiServer     bool `yaml:"chi-server,omitempty"`     // ChiServer specifies whether to generate chi server boilerplate
+	EchoServer    bool `yaml:"echo-server,omitempty"`    // EchoServer specifies whether to generate echo server boilerplate
+	GinServer     bool `yaml:"gin-server,omitempty"`     // GinServer specifies whether to generate echo server boilerplate
+	GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate
+	Client        bool `yaml:"client,omitempty"`         // Client specifies whether to generate client boilerplate
+	Models        bool `yaml:"models,omitempty"`         // Models specifies whether to generate type definitions
+	EmbeddedSpec  bool `yaml:"embedded-spec,omitempty"`  // Whether to embed the swagger spec in the generated code
+}
+
+// CompatibilityOptions specifies backward compatibility settings for the
+// code generator.
+type CompatibilityOptions struct {
+	// In the past, we merged schemas for `allOf` by inlining each schema
+	// within the schema list. This approach, though, is incorrect because
+	// `allOf` merges at the schema definition level, not at the resulting model
+	// level. So, new behavior merges OpenAPI specs but generates different code
+	// than we have in the past. Set OldMergeSchemas to true for the old behavior.
+	// Please see https://github.com/deepmap/oapi-codegen/issues/531
+	OldMergeSchemas bool `yaml:"old-merge-schemas"`
+	// Enum values can generate conflicting typenames, so we've updated the
+	// code for enum generation to avoid these conflicts, but it will result
+	// in some enum types being renamed in existing code. Set OldEnumConflicts to true
+	// to revert to old behavior. Please see:
+	// Please see https://github.com/deepmap/oapi-codegen/issues/549
+	OldEnumConflicts bool `yaml:"old-enum-conflicts"`
+	// It was a mistake to generate a go type definition for every $ref in
+	// the OpenAPI schema. New behavior uses type aliases where possible, but
+	// this can generate code which breaks existing builds. Set OldAliasing to true
+	// for old behavior.
+	// Please see https://github.com/deepmap/oapi-codegen/issues/549
+	OldAliasing bool `yaml:"old-aliasing"`
+}
+
+// OutputOptions are used to modify the output code in some way.
+type OutputOptions struct {
+	SkipFmt       bool              `yaml:"skip-fmt,omitempty"`       // Whether to skip go imports on the generated code
+	SkipPrune     bool              `yaml:"skip-prune,omitempty"`     // Whether to skip pruning unused components on the generated code
+	IncludeTags   []string          `yaml:"include-tags,omitempty"`   // Only include operations that have one of these tags. Ignored when empty.
+	ExcludeTags   []string          `yaml:"exclude-tags,omitempty"`   // Exclude operations that have one of these tags. Ignored when empty.
+	UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files
+
+	ExcludeSchemas     []string `yaml:"exclude-schemas,omitempty"`      // Exclude from generation schemas with given names. Ignored when empty.
+	ResponseTypeSuffix string   `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types
+}
+
+// UpdateDefaults sets reasonable default values for unset fields in Configuration
+func (o Configuration) UpdateDefaults() Configuration {
+	if reflect.ValueOf(o.Generate).IsZero() {
+		o.Generate = GenerateOptions{
+			EchoServer:   true,
+			Models:       true,
+			EmbeddedSpec: true,
+		}
+	}
+	return o
+}
+
+// Validate checks whether Configuration represent a valid configuration
+func (o Configuration) Validate() error {
+	if o.PackageName == "" {
+		return errors.New("package name must be specified")
+	}
+
+	// Only one server type should be specified at a time.
+	nServers := 0
+	if o.Generate.ChiServer {
+		nServers++
+	}
+	if o.Generate.EchoServer {
+		nServers++
+	}
+	if o.Generate.GinServer {
+		nServers++
+	}
+	if nServers > 1 {
+		return errors.New("only one server type is supported at a time")
+	}
+	return nil
+}
diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go
index 28294b1..e986b3f 100644
--- a/pkg/codegen/extension.go
+++ b/pkg/codegen/extension.go
@@ -7,7 +7,7 @@ import (
 
 const (
 	extPropGoType    = "x-go-type"
-	extGoFieldName   = "x-go-name"
+	extGoName        = "x-go-name"
 	extPropOmitEmpty = "x-omitempty"
 	extPropExtraTags = "x-oapi-codegen-extra-tags"
 )
diff --git a/pkg/codegen/filter.go b/pkg/codegen/filter.go
index bf65b59..56c9730 100644
--- a/pkg/codegen/filter.go
+++ b/pkg/codegen/filter.go
@@ -2,12 +2,12 @@ package codegen
 
 import "github.com/getkin/kin-openapi/openapi3"
 
-func filterOperationsByTag(swagger *openapi3.T, opts Options) {
-	if len(opts.ExcludeTags) > 0 {
-		excludeOperationsWithTags(swagger.Paths, opts.ExcludeTags)
+func filterOperationsByTag(swagger *openapi3.T, opts Configuration) {
+	if len(opts.OutputOptions.ExcludeTags) > 0 {
+		excludeOperationsWithTags(swagger.Paths, opts.OutputOptions.ExcludeTags)
 	}
-	if len(opts.IncludeTags) > 0 {
-		includeOperationsWithTags(swagger.Paths, opts.IncludeTags, false)
+	if len(opts.OutputOptions.IncludeTags) > 0 {
+		includeOperationsWithTags(swagger.Paths, opts.OutputOptions.IncludeTags, false)
 	}
 }
 
diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go
index 5bf378b..1ac358d 100644
--- a/pkg/codegen/merge_schemas.go
+++ b/pkg/codegen/merge_schemas.go
@@ -12,22 +12,28 @@ import (
 func MergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
 	// If someone asked for the old way, for backward compatibility, return the
 	// old style result.
-	if options.OldMergeSchemas {
+	if globalState.options.Compatibility.OldMergeSchemas {
 		return mergeSchemas_V1(allOf, path)
 	}
 	return mergeSchemas(allOf, path)
 }
 
 func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
-	var schema openapi3.Schema
-	for _, schemaRef := range allOf {
+	n := len(allOf)
+
+	if n == 1 {
+		return GenerateGoSchema(allOf[0], path)
+	}
+
+	schema := *allOf[0].Value
+
+	for i := 1; i < n; i++ {
 		var err error
-		schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value)
+		schema, err = mergeOpenapiSchemas(schema, *allOf[i].Value)
 		if err != nil {
 			return Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
 		}
 	}
-
 	return GenerateGoSchema(openapi3.NewSchemaRef("", &schema), path)
 }
 
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index fe2d66b..e858482 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -120,8 +120,8 @@ func (pd ParameterDefinition) GoVariableName() string {
 
 func (pd ParameterDefinition) GoName() string {
 	goName := pd.ParamName
-	if _, ok := pd.Spec.ExtensionProps.Extensions[extGoFieldName]; ok {
-		if extGoFieldName, err := extParseGoFieldName(pd.Spec.ExtensionProps.Extensions[extGoFieldName]); err == nil {
+	if _, ok := pd.Spec.ExtensionProps.Extensions[extGoName]; ok {
+		if extGoFieldName, err := extParseGoFieldName(pd.Spec.ExtensionProps.Extensions[extGoName]); err == nil {
 			goName = extGoFieldName
 		}
 	}
@@ -683,6 +683,12 @@ func GenerateGinServer(t *template.Template, operations []OperationDefinition) (
 	return GenerateTemplates([]string{"gin/gin-interface.tmpl", "gin/gin-wrappers.tmpl", "gin/gin-register.tmpl"}, t, operations)
 }
 
+// GenerateGinServer This function generates all the go code for the ServerInterface as well as
+// all the wrapper functions around our handlers.
+func GenerateGorillaServer(t *template.Template, operations []OperationDefinition) (string, error) {
+	return GenerateTemplates([]string{"gorilla/gorilla-interface.tmpl", "gorilla/gorilla-middleware.tmpl", "gorilla/gorilla-register.tmpl"}, t, operations)
+}
+
 // Uses the template engine to generate the function which registers our wrappers
 // as Echo path handlers.
 func GenerateClient(t *template.Template, ops []OperationDefinition) (string, error) {
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index 13f2a81..2b44397 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -8,7 +8,8 @@ import (
 	"github.com/getkin/kin-openapi/openapi3"
 )
 
-// This describes a Schema, a type definition.
+// Schema describes an OpenAPI schema, with lots of helper fields to use in the
+// templating engine.
 type Schema struct {
 	GoType  string // The Go type needed to represent the schema
 	RefType string // If the type has a type name, this is set
@@ -26,6 +27,11 @@ type Schema struct {
 
 	Description string // The description of the element
 
+	// If this is set, the schema will declare a type via alias, eg,
+	// `type Foo = bool`. If this is not set, we will define this type via
+	// type definition `type Foo bool`
+	DefineViaAlias bool
+
 	// The original OpenAPIv3 Schema.
 	OAPISchema *openapi3.Schema
 }
@@ -162,9 +168,8 @@ type ResponseTypeDefinition struct {
 	ResponseName string
 }
 
-func (t *TypeDefinition) CanAlias() bool {
-	return t.Schema.IsRef() || /* actual reference */
-		(t.Schema.ArrayType != nil && t.Schema.ArrayType.IsRef()) /* array to ref */
+func (t *TypeDefinition) IsAlias() bool {
+	return !globalState.options.Compatibility.OldAliasing && t.Schema.DefineViaAlias
 }
 
 func PropertiesEqual(a, b Property) bool {
@@ -191,8 +196,9 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 				sref.Ref, err)
 		}
 		return Schema{
-			GoType:      refType,
-			Description: StringToGoComment(schema.Description),
+			GoType:         refType,
+			Description:    StringToGoComment(schema.Description),
+			DefineViaAlias: true,
 		}, nil
 	}
 
@@ -254,7 +260,11 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 				outType = "interface{}"
 			}
 			outSchema.GoType = outType
+			outSchema.DefineViaAlias = true
 		} else {
+			// When we define an object, we want it to be a type definition,
+			// not a type alias, eg, "type Foo struct {...}"
+			outSchema.DefineViaAlias = false
 			// We've got an object with some properties.
 			for _, pName := range SortedSchemaKeys(schema.Properties) {
 				p := schema.Properties[pName]
@@ -315,7 +325,12 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 		}
 		return outSchema, nil
 	} else if len(schema.Enum) > 0 {
-		err := resolveType(schema, path, &outSchema)
+		err := oapiSchemaToGoType(schema, path, &outSchema)
+		// Enums need to be typed, so that the values aren't interchangeable,
+		// so no matter what schema conversion thinks, we need to define a
+		// new type.
+		outSchema.DefineViaAlias = false
+
 		if err != nil {
 			return Schema{}, fmt.Errorf("error resolving primitive type: %w", err)
 		}
@@ -334,7 +349,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 			} else {
 				enumName = k
 			}
-			if options.OldEnumConflicts {
+			if globalState.options.Compatibility.OldEnumConflicts {
 				outSchema.EnumValues[SchemaNameToTypeName(PathToTypeName(append(path, enumName)))] = v
 			} else {
 				outSchema.EnumValues[SchemaNameToTypeName(k)] = v
@@ -352,7 +367,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 		}
 		//outSchema.RefType = typeName
 	} else {
-		err := resolveType(schema, path, &outSchema)
+		err := oapiSchemaToGoType(schema, path, &outSchema)
 		if err != nil {
 			return Schema{}, fmt.Errorf("error resolving primitive type: %w", err)
 		}
@@ -360,8 +375,9 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 	return outSchema, nil
 }
 
-// resolveType resolves primitive  type or array for schema
-func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) error {
+// oapiSchemaToGoType converts an OpenApi schema into a Go type definition for
+// all non-object types.
+func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schema) error {
 	f := schema.Format
 	t := schema.Type
 
@@ -377,6 +393,7 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro
 		outSchema.GoType = "[]" + arrayType.TypeDecl()
 		outSchema.AdditionalTypes = arrayType.AdditionalTypes
 		outSchema.Properties = arrayType.Properties
+		outSchema.DefineViaAlias = true
 	case "integer":
 		// We default to int if format doesn't ask for something else.
 		if f == "int64" {
@@ -404,6 +421,7 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro
 		} else {
 			return fmt.Errorf("invalid integer format: %s", f)
 		}
+		outSchema.DefineViaAlias = true
 	case "number":
 		// We default to float for "number"
 		if f == "double" {
@@ -413,11 +431,13 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro
 		} else {
 			return fmt.Errorf("invalid number format: %s", f)
 		}
+		outSchema.DefineViaAlias = true
 	case "boolean":
 		if f != "" {
 			return fmt.Errorf("invalid format (%s) for boolean", f)
 		}
 		outSchema.GoType = "bool"
+		outSchema.DefineViaAlias = true
 	case "string":
 		// Special case string formats here.
 		switch f {
@@ -438,13 +458,14 @@ func resolveType(schema *openapi3.Schema, path []string, outSchema *Schema) erro
 			// All unrecognized formats are simply a regular string.
 			outSchema.GoType = "string"
 		}
+		outSchema.DefineViaAlias = true
 	default:
 		return fmt.Errorf("unhandled Schema type: %s", t)
 	}
 	return nil
 }
 
-// This describes a Schema, a type definition.
+// SchemaDescriptor describes a Schema, a type definition.
 type SchemaDescriptor struct {
 	Fields                   []FieldDescriptor
 	HasAdditionalProperties  bool
@@ -476,8 +497,8 @@ func GenFieldsFromProperties(props []Property) []string {
 		}
 
 		goFieldName := p.GoFieldName()
-		if _, ok := p.ExtensionProps.Extensions[extGoFieldName]; ok {
-			if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoFieldName]); err == nil {
+		if _, ok := p.ExtensionProps.Extensions[extGoName]; ok {
+			if extGoFieldName, err := extParseGoFieldName(p.ExtensionProps.Extensions[extGoName]); err == nil {
 				goFieldName = extGoFieldName
 			}
 		}
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index eeb7810..3ff5e1e 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -274,6 +274,7 @@ var TemplateFunctions = template.FuncMap{
 	"swaggerUriToEchoUri":        SwaggerUriToEchoUri,
 	"swaggerUriToChiUri":         SwaggerUriToChiUri,
 	"swaggerUriToGinUri":         SwaggerUriToGinUri,
+	"swaggerUriToGorillaUri":     SwaggerUriToGorillaUri,
 	"lcFirst":                    LowercaseFirstCharacter,
 	"ucFirst":                    UppercaseFirstCharacter,
 	"camelCase":                  ToCamelCase,
diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl
index 53a44d3..30270cc 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -5,7 +5,7 @@ type ServerInterfaceWrapper struct {
     ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
 }
 
-type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
+type MiddlewareFunc func(http.Handler) http.Handler
 
 {{range .}}{{$opid := .OperationId}}
 
@@ -30,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
   }
   {{end}}
   {{if .IsStyled}}
-  err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", chi.URLParam(r, "{{.ParamName}}"), &{{$varName}})
+  err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, chi.URLParam(r, "{{.ParamName}}"), &{{$varName}})
   if err != nil {
     siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
     return
@@ -168,15 +168,15 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
     {{end}}
   {{end}}
 
-  var handler = func(w http.ResponseWriter, r *http.Request) {
+  var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
-}
+  })
 
   for _, middleware := range siw.HandlerMiddlewares {
     handler = middleware(handler)
   }
 
-  handler(w, r.WithContext(ctx))
+  handler.ServeHTTP(w, r.WithContext(ctx))
 }
 {{end}}
 
diff --git a/pkg/codegen/templates/gorilla/gorilla-interface.tmpl b/pkg/codegen/templates/gorilla/gorilla-interface.tmpl
new file mode 100644
index 0000000..79a51fd
--- /dev/null
+++ b/pkg/codegen/templates/gorilla/gorilla-interface.tmpl
@@ -0,0 +1,7 @@
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+{{range .}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
+{{end}}
+}
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
new file mode 100644
index 0000000..a08bc5e
--- /dev/null
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -0,0 +1,251 @@
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+    Handler ServerInterface
+    HandlerMiddlewares []MiddlewareFunc
+    ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
+
+{{range .}}{{$opid := .OperationId}}
+
+// {{$opid}} operation middleware
+func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Request) {
+  ctx := r.Context()
+  {{if or .RequiresParamObject (gt (len .PathParams) 0) }}
+  var err error
+  {{end}}
+
+  {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
+  var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
+
+  {{if .IsPassThrough}}
+  {{$varName}} = mux.Vars(r)["{{.ParamName}}"]
+  {{end}}
+  {{if .IsJson}}
+  err = json.Unmarshal([]byte(mux.Vars(r)["{{.ParamName}}"]), &{{$varName}})
+  if err != nil {
+    siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+    return
+  }
+  {{end}}
+  {{if .IsStyled}}
+  err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", mux.Vars(r)["{{.ParamName}}"], &{{$varName}})
+  if err != nil {
+    siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+    return
+  }
+  {{end}}
+
+  {{end}}
+
+{{range .SecurityDefinitions}}
+  ctx = context.WithValue(ctx, {{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+{{end}}
+
+  {{if .RequiresParamObject}}
+    // Parameter object where we will unmarshal all parameters from the context
+    var params {{.OperationId}}Params
+
+    {{range $paramIdx, $param := .QueryParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+      if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
+
+      {{if .IsPassThrough}}
+        params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+      {{end}}
+
+      {{if .IsJson}}
+        var value {{.TypeDef}}
+        err = json.Unmarshal([]byte(paramValue), &value)
+        if err != nil {
+          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+          return
+        }
+
+        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+      {{end}}
+      }{{if .Required}} else {
+          siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+          return
+      }{{end}}
+      {{if .IsStyled}}
+      err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), &params.{{.GoName}})
+      if err != nil {
+        siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+        return
+      }
+      {{end}}
+  {{end}}
+
+    {{if .HeaderParams}}
+      headers := r.Header
+
+      {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
+        if valueList, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+          var {{.GoName}} {{.TypeDef}}
+          n := len(valueList)
+          if n != 1 {
+            siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{.ParamName}}", Count: n})
+            return
+          }
+
+        {{if .IsPassThrough}}
+          params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+        {{end}}
+
+        {{if .IsJson}}
+          err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
+          if err != nil {
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+            return
+          }
+        {{end}}
+
+        {{if .IsStyled}}
+          err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+          if err != nil {
+            siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+            return
+          }
+        {{end}}
+
+          params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+
+        } {{if .Required}}else {
+            err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
+            siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{.ParamName}}", Err: err})
+            return
+        }{{end}}
+
+      {{end}}
+    {{end}}
+
+    {{range .CookieParams}}
+      var cookie *http.Cookie
+
+      if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
+
+      {{- if .IsPassThrough}}
+        params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+      {{end}}
+
+      {{- if .IsJson}}
+        var value {{.TypeDef}}
+        var decoded string
+        decoded, err := url.QueryUnescape(cookie.Value)
+        if err != nil {
+          err = fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'")
+          siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{.ParamName}}", Err: err})
+          return
+        }
+
+        err = json.Unmarshal([]byte(decoded), &value)
+        if err != nil {
+          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+          return
+        }
+
+        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+      {{end}}
+
+      {{- if .IsStyled}}
+        var value {{.TypeDef}}
+        err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
+        if err != nil {
+          siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+          return
+        }
+        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+      {{end}}
+
+      }
+
+      {{- if .Required}} else {
+        siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+        return
+      }
+      {{- end}}
+    {{end}}
+  {{end}}
+
+  var handler = func(w http.ResponseWriter, r *http.Request) {
+    siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+}
+
+  for _, middleware := range siw.HandlerMiddlewares {
+    handler = middleware(handler)
+  }
+
+  handler(w, r.WithContext(ctx))
+}
+{{end}}
+
+type UnescapedCookieParamError struct {
+    ParamName string
+    Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+    return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+    return e.Err
+}
+
+type UnmarshalingParamError struct {
+    ParamName string
+    Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+    return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+    return e.Err
+}
+
+type RequiredParamError struct {
+    ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+    return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+    ParamName string
+    Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+    return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+    return e.Err
+}
+
+type InvalidParamFormatError struct {
+    ParamName string
+	  Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+    return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+    return e.Err
+}
+
+type TooManyValuesForParamError struct {
+    ParamName string
+    Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+    return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
diff --git a/pkg/codegen/templates/gorilla/gorilla-register.tmpl b/pkg/codegen/templates/gorilla/gorilla-register.tmpl
new file mode 100644
index 0000000..b019e1d
--- /dev/null
+++ b/pkg/codegen/templates/gorilla/gorilla-register.tmpl
@@ -0,0 +1,49 @@
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+  return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+    BaseURL string
+    BaseRouter *mux.Router
+    Middlewares []MiddlewareFunc
+    ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+    return HandlerWithOptions(si, GorillaServerOptions {
+        BaseRouter: r,
+    })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+    return HandlerWithOptions(si, GorillaServerOptions {
+        BaseURL: baseURL,
+        BaseRouter: r,
+    })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+r := options.BaseRouter
+
+if r == nil {
+r = mux.NewRouter()
+}
+if options.ErrorHandlerFunc == nil {
+    options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+        http.Error(w, err.Error(), http.StatusBadRequest)
+    }
+}
+{{if .}}wrapper := ServerInterfaceWrapper{
+Handler: si,
+HandlerMiddlewares: options.Middlewares,
+ErrorHandlerFunc: options.ErrorHandlerFunc,
+}
+{{end}}
+{{range .}}
+r.HandleFunc(options.BaseURL+"{{.Path | swaggerUriToGorillaUri }}", wrapper.{{.OperationId}}).Methods("{{.Method }}")
+{{end}}
+return r
+}
diff --git a/pkg/codegen/templates/param-types.tmpl b/pkg/codegen/templates/param-types.tmpl
index f49ba30..bb107b8 100644
--- a/pkg/codegen/templates/param-types.tmpl
+++ b/pkg/codegen/templates/param-types.tmpl
@@ -1,6 +1,6 @@
 {{range .}}{{$opid := .OperationId}}
 {{range .TypeDefinitions}}
 // {{.TypeName}} defines parameters for {{$opid}}.
-type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
+type {{.TypeName}} {{if .IsAlias}}={{end}} {{.Schema.TypeDecl}}
 {{end}}
 {{end}}
diff --git a/pkg/codegen/templates/request-bodies.tmpl b/pkg/codegen/templates/request-bodies.tmpl
index 313dd11..d970ce7 100644
--- a/pkg/codegen/templates/request-bodies.tmpl
+++ b/pkg/codegen/templates/request-bodies.tmpl
@@ -2,7 +2,7 @@
 {{range .Bodies}}
 {{with .TypeDef $opid}}
 // {{.TypeName}} defines body for {{$opid}} for application/json ContentType.
-type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
+type {{.TypeName}} {{if .IsAlias}}={{end}} {{.Schema.TypeDecl}}
 {{end}}
 {{end}}
 {{end}}
diff --git a/pkg/codegen/templates/typedef.tmpl b/pkg/codegen/templates/typedef.tmpl
index 0b153b7..e5a6a82 100644
--- a/pkg/codegen/templates/typedef.tmpl
+++ b/pkg/codegen/templates/typedef.tmpl
@@ -1,4 +1,4 @@
 {{range .Types}}
 {{ with .Schema.Description }}{{ . }}{{ else }}// {{.TypeName}} defines model for {{.JsonName}}.{{ end }}
-type {{.TypeName}} {{if and (opts.AliasTypes) (.CanAlias)}}={{end}} {{.Schema.TypeDecl}}
+type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}}
 {{end}}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index a7dc3cf..c713002 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -205,7 +205,7 @@ func StringInArray(str string, array []string) bool {
 	return false
 }
 
-// This function takes a $ref value and converts it to a Go typename.
+// RefPathToGoType takes a $ref value and converts it to a Go typename.
 // #/components/schemas/Foo -> Foo
 // #/components/parameters/Bar -> Bar
 // #/components/responses/Baz -> Baz
@@ -228,7 +228,20 @@ func refPathToGoType(refPath string, local bool) (string, error) {
 		} else if depth != 4 && depth != 2 {
 			return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
 		}
-		return SchemaNameToTypeName(pathParts[len(pathParts)-1]), nil
+
+		// Schemas may have been renamed locally, so look up the actual name in
+		// the spec.
+		name, err := findSchemaNameByRefPath(refPath, globalState.spec)
+		if err != nil {
+			return "", fmt.Errorf("error finding ref: %s in spec: %v", refPath, err)
+		}
+		if name != "" {
+			return name, nil
+		}
+		// lastPart now stores the final element of the type path. This is what
+		// we use as the base for a type name.
+		lastPart := pathParts[len(pathParts)-1]
+		return SchemaNameToTypeName(lastPart), nil
 	}
 	pathParts := strings.Split(refPath, "#")
 	if len(pathParts) != 2 {
@@ -246,7 +259,7 @@ func refPathToGoType(refPath string, local bool) (string, error) {
 	}
 }
 
-// This function takes a $ref value and checks if it has link to go type.
+// IsGoTypeReference takes a $ref value and checks if it has link to go type.
 // #/components/schemas/Foo                     -> true
 // ./local/file.yml#/components/parameters/Bar  -> true
 // ./local/file.yml                             -> false
@@ -256,7 +269,7 @@ func IsGoTypeReference(ref string) bool {
 	return ref != "" && !IsWholeDocumentReference(ref)
 }
 
-// This function takes a $ref value and checks if it is whole document reference.
+// IsWholeDocumentReference takes a $ref value and checks if it is whole document reference.
 // #/components/schemas/Foo                             -> false
 // ./local/file.yml#/components/parameters/Bar          -> false
 // ./local/file.yml                                     -> true
@@ -267,8 +280,8 @@ func IsWholeDocumentReference(ref string) bool {
 	return ref != "" && !strings.ContainsAny(ref, "#")
 }
 
-// This function converts a swagger style path URI with parameters to a
-// Echo compatible path URI. We need to replace all of Swagger parameters with
+// SwaggerUriToEchoUri converts a OpenAPI style path URI with parameters to a
+// Echo compatible path URI. We need to replace all of OpenAPI parameters with
 // ":param". Valid input parameters are:
 //   {param}
 //   {param*}
@@ -282,7 +295,7 @@ func SwaggerUriToEchoUri(uri string) string {
 	return pathParamRE.ReplaceAllString(uri, ":$1")
 }
 
-// This function converts a swagger style path URI with parameters to a
+// SwaggerUriToChiUri converts a swagger style path URI with parameters to a
 // Chi compatible path URI. We need to replace all of Swagger parameters with
 // "{param}". Valid input parameters are:
 //   {param}
@@ -312,6 +325,21 @@ func SwaggerUriToGinUri(uri string) string {
 	return pathParamRE.ReplaceAllString(uri, ":$1")
 }
 
+// This function converts a swagger style path URI with parameters to a
+// Gorilla compatible path URI. We need to replace all of Swagger parameters with
+// ":param". Valid input parameters are:
+//   {param}
+//   {param*}
+//   {.param}
+//   {.param*}
+//   {;param}
+//   {;param*}
+//   {?param}
+//   {?param*}
+func SwaggerUriToGorillaUri(uri string) string {
+	return pathParamRE.ReplaceAllString(uri, "{$1}")
+}
+
 // Returns the argument names, in order, in a given URI string, so for
 // /path/{param1}/{.param2*}/{?param3}, it would return param1, param2, param3
 func OrderedParamsFromUri(uri string) []string {
@@ -535,6 +563,9 @@ func SanitizeEnumNames(enumNames []string) map[string]string {
 }
 
 func typeNamePrefix(name string) (prefix string) {
+	if len(name) == 0 {
+		return "Empty"
+	}
 	for _, r := range name {
 		switch r {
 		case '$':
@@ -547,6 +578,8 @@ func typeNamePrefix(name string) (prefix string) {
 			prefix += "Plus"
 		case '&':
 			prefix += "And"
+		case '|':
+			prefix += "Or"
 		case '~':
 			prefix += "Tilde"
 		case '=':
@@ -555,6 +588,10 @@ func typeNamePrefix(name string) (prefix string) {
 			prefix += "Hash"
 		case '.':
 			prefix += "Dot"
+		case '*':
+			prefix += "Asterisk"
+		case '^':
+			prefix += "Caret"
 		default:
 			// Prepend "N" to schemas starting with a number
 			if prefix == "" && unicode.IsDigit(r) {
@@ -638,3 +675,118 @@ func EscapePathElements(path string) string {
 	}
 	return strings.Join(elems, "/")
 }
+
+// renameSchema takes as input the name of a schema as provided in the spec,
+// and the definition of the schema. If the schema overrides the name via
+// x-go-name, the new name is returned, otherwise, the original name is
+// returned.
+func renameSchema(schemaName string, schemaRef *openapi3.SchemaRef) (string, error) {
+	// References will not change type names.
+	if schemaRef.Ref != "" {
+		return SchemaNameToTypeName(schemaName), nil
+	}
+	schema := schemaRef.Value
+
+	if extension, ok := schema.Extensions[extGoName]; ok {
+		typeName, err := extTypeName(extension)
+		if err != nil {
+			return "", fmt.Errorf("invalid value for %q: %w", extPropGoType, err)
+		}
+		return typeName, nil
+	}
+	return SchemaNameToTypeName(schemaName), nil
+}
+
+// renameParameter generates the name for a parameter, taking x-go-name into
+// account
+func renameParameter(parameterName string, parameterRef *openapi3.ParameterRef) (string, error) {
+	if parameterRef.Ref != "" {
+		return SchemaNameToTypeName(parameterName), nil
+	}
+	parameter := parameterRef.Value
+
+	if extension, ok := parameter.Extensions[extGoName]; ok {
+		typeName, err := extTypeName(extension)
+		if err != nil {
+			return "", fmt.Errorf("invalid value for %q: %w", extPropGoType, err)
+		}
+		return typeName, nil
+	}
+	return SchemaNameToTypeName(parameterName), nil
+}
+
+// renameResponse generates the name for a parameter, taking x-go-name into
+// account
+func renameResponse(responseName string, responseRef *openapi3.ResponseRef) (string, error) {
+	if responseRef.Ref != "" {
+		return SchemaNameToTypeName(responseName), nil
+	}
+	response := responseRef.Value
+
+	if extension, ok := response.Extensions[extGoName]; ok {
+		typeName, err := extTypeName(extension)
+		if err != nil {
+			return "", fmt.Errorf("invalid value for %q: %w", extPropGoType, err)
+		}
+		return typeName, nil
+	}
+	return SchemaNameToTypeName(responseName), nil
+}
+
+// renameRequestBody generates the name for a parameter, taking x-go-name into
+// account
+func renameRequestBody(requestBodyName string, requestBodyRef *openapi3.RequestBodyRef) (string, error) {
+	if requestBodyRef.Ref != "" {
+		return SchemaNameToTypeName(requestBodyName), nil
+	}
+	requestBody := requestBodyRef.Value
+
+	if extension, ok := requestBody.Extensions[extGoName]; ok {
+		typeName, err := extTypeName(extension)
+		if err != nil {
+			return "", fmt.Errorf("invalid value for %q: %w", extPropGoType, err)
+		}
+		return typeName, nil
+	}
+	return SchemaNameToTypeName(requestBodyName), nil
+}
+
+// findSchemaByRefPath turns a $ref path into a schema. This will return ""
+// if the schema wasn't found, and it'll only work successfully for schemas
+// defined within the spec that we parsed.
+func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) {
+	pathElements := strings.Split(refPath, "/")
+	// All local references will have 4 path elements.
+	if len(pathElements) != 4 {
+		return "", nil
+	}
+
+	// We only support local references
+	if pathElements[0] != "#" {
+		return "", nil
+	}
+	// Only components are supported
+	if pathElements[1] != "components" {
+		return "", nil
+	}
+	propertyName := pathElements[3]
+	switch pathElements[2] {
+	case "schemas":
+		if schema, found := spec.Components.Schemas[propertyName]; found {
+			return renameSchema(propertyName, schema)
+		}
+	case "parameters":
+		if parameter, found := spec.Components.Parameters[propertyName]; found {
+			return renameParameter(propertyName, parameter)
+		}
+	case "responses":
+		if response, found := spec.Components.Responses[propertyName]; found {
+			return renameResponse(propertyName, response)
+		}
+	case "requestBodies":
+		if requestBody, found := spec.Components.RequestBodies[propertyName]; found {
+			return renameRequestBody(propertyName, requestBody)
+		}
+	}
+	return "", nil
+}


Test patch:
diff --git a/examples/petstore-expanded/gorilla/petstore_test.go b/examples/petstore-expanded/gorilla/petstore_test.go
new file mode 100644
index 0000000..c325326
--- /dev/null
+++ b/examples/petstore-expanded/gorilla/petstore_test.go
@@ -0,0 +1,168 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/gorilla/mux"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/deepmap/oapi-codegen/examples/petstore-expanded/gorilla/api"
+	middleware "github.com/deepmap/oapi-codegen/pkg/chi-middleware"
+	"github.com/deepmap/oapi-codegen/pkg/testutil"
+)
+
+func doGet(t *testing.T, mux *mux.Router, url string) *httptest.ResponseRecorder {
+	response := testutil.NewRequest().Get(url).WithAcceptJson().GoWithHTTPHandler(t, mux)
+	return response.Recorder
+}
+
+func TestPetStore(t *testing.T) {
+	var err error
+
+	// Get the swagger description of our API
+	swagger, err := api.GetSwagger()
+	require.NoError(t, err)
+
+	// Clear out the servers array in the swagger spec, that skips validating
+	// that server names match. We don't know how this thing will be run.
+	swagger.Servers = nil
+
+	// This is how you set up a basic Gorilla router
+	r := mux.NewRouter()
+
+	// Use our validation middleware to check all requests against the
+	// OpenAPI schema.
+	r.Use(middleware.OapiRequestValidator(swagger))
+
+	store := api.NewPetStore()
+	api.HandlerFromMux(store, r)
+
+	t.Run("Add pet", func(t *testing.T) {
+		tag := "TagOfSpot"
+		newPet := api.NewPet{
+			Name: "Spot",
+			Tag:  &tag,
+		}
+
+		rr := testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, r).Recorder
+		assert.Equal(t, http.StatusCreated, rr.Code)
+
+		var resultPet api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&resultPet)
+		assert.NoError(t, err, "error unmarshaling response")
+		assert.Equal(t, newPet.Name, resultPet.Name)
+		assert.Equal(t, *newPet.Tag, *resultPet.Tag)
+	})
+
+	t.Run("Find pet by ID", func(t *testing.T) {
+		pet := api.Pet{
+			Id: 100,
+		}
+
+		store.Pets[pet.Id] = pet
+		rr := doGet(t, r, fmt.Sprintf("/pets/%d", pet.Id))
+
+		var resultPet api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&resultPet)
+		assert.NoError(t, err, "error getting pet")
+		assert.Equal(t, pet, resultPet)
+	})
+
+	t.Run("Pet not found", func(t *testing.T) {
+		rr := doGet(t, r, "/pets/27179095781")
+		assert.Equal(t, http.StatusNotFound, rr.Code)
+
+		var petError api.Error
+		err = json.NewDecoder(rr.Body).Decode(&petError)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+	})
+
+	t.Run("List all pets", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{
+			1: api.Pet{},
+			2: api.Pet{},
+		}
+
+		// Now, list all pets, we should have two
+		rr := doGet(t, r, "/pets")
+		assert.Equal(t, http.StatusOK, rr.Code)
+
+		var petList []api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 2, len(petList))
+	})
+
+	t.Run("Filter pets by tag", func(t *testing.T) {
+		tag := "TagOfFido"
+
+		store.Pets = map[int64]api.Pet{
+			1: {
+				Tag: &tag,
+			},
+			2: {},
+		}
+
+		// Filter pets by tag, we should have 1
+		rr := doGet(t, r, "/pets?tags=TagOfFido")
+		assert.Equal(t, http.StatusOK, rr.Code)
+
+		var petList []api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 1, len(petList))
+	})
+
+	t.Run("Filter pets by tag", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{
+			1: api.Pet{},
+			2: api.Pet{},
+		}
+
+		// Filter pets by non existent tag, we should have 0
+		rr := doGet(t, r, "/pets?tags=NotExists")
+		assert.Equal(t, http.StatusOK, rr.Code)
+
+		var petList []api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 0, len(petList))
+	})
+
+	t.Run("Delete pets", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{
+			1: api.Pet{},
+			2: api.Pet{},
+		}
+
+		// Let's delete non-existent pet
+		rr := testutil.NewRequest().Delete("/pets/7").GoWithHTTPHandler(t, r).Recorder
+		assert.Equal(t, http.StatusNotFound, rr.Code)
+
+		var petError api.Error
+		err = json.NewDecoder(rr.Body).Decode(&petError)
+		assert.NoError(t, err, "error unmarshaling PetError")
+		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+
+		// Now, delete both real pets
+		rr = testutil.NewRequest().Delete("/pets/1").GoWithHTTPHandler(t, r).Recorder
+		assert.Equal(t, http.StatusNoContent, rr.Code)
+
+		rr = testutil.NewRequest().Delete("/pets/2").GoWithHTTPHandler(t, r).Recorder
+		assert.Equal(t, http.StatusNoContent, rr.Code)
+
+		// Should have no pets left.
+		var petList []api.Pet
+		rr = doGet(t, r, "/pets")
+		assert.Equal(t, http.StatusOK, rr.Code)
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 0, len(petList))
+	})
+}
diff --git a/internal/test/all_of/config1.yaml b/internal/test/all_of/config1.yaml
index 927b1da..570e560 100644
--- a/internal/test/all_of/config1.yaml
+++ b/internal/test/all_of/config1.yaml
@@ -5,4 +5,5 @@ generate:
   - types
   - skip-prune
   - spec
-old-all-of-output: true
+compatibility:
+  old-merge-schemas: true
diff --git a/internal/test/all_of/doc.go b/internal/test/all_of/doc.go
index 0740268..af048d8 100644
--- a/internal/test/all_of/doc.go
+++ b/internal/test/all_of/doc.go
@@ -1,4 +1,4 @@
 package all_of
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config1.yaml openapi.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config2.yaml openapi.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --config=config1.yaml openapi.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --config=config2.yaml openapi.yaml
diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go
index abea3b4..2319a55 100644
--- a/internal/test/client/client.gen.go
+++ b/internal/test/client/client.gen.go
@@ -32,16 +32,16 @@ type SchemaObject struct {
 }
 
 // PostBothJSONBody defines parameters for PostBoth.
-type PostBothJSONBody SchemaObject
+type PostBothJSONBody = SchemaObject
 
 // PostJsonJSONBody defines parameters for PostJson.
-type PostJsonJSONBody SchemaObject
+type PostJsonJSONBody = SchemaObject
 
 // PostBothJSONRequestBody defines body for PostBoth for application/json ContentType.
-type PostBothJSONRequestBody PostBothJSONBody
+type PostBothJSONRequestBody = PostBothJSONBody
 
 // PostJsonJSONRequestBody defines body for PostJson for application/json ContentType.
-type PostJsonJSONRequestBody PostJsonJSONBody
+type PostJsonJSONRequestBody = PostJsonJSONBody
 
 // RequestEditorFn  is the function signature for the RequestEditor callback function
 type RequestEditorFn func(ctx context.Context, req *http.Request) error
diff --git a/internal/test/client/doc.go b/internal/test/client/doc.go
index 8244197..6a97107 100644
--- a/internal/test/client/doc.go
+++ b/internal/test/client/doc.go
@@ -1,3 +1,3 @@
 package client
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=client -o client.gen.go client.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=client -o client.gen.go client.yaml
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index 7387fcf..aad97ec 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -4,16 +4,8 @@
 package components
 
 import (
-	"bytes"
-	"compress/gzip"
-	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"net/url"
-	"path"
-	"strings"
-
-	"github.com/getkin/kin-openapi/openapi3"
 )
 
 // Defines values for Enum1.
@@ -25,7 +17,7 @@ const (
 
 // Defines values for Enum2.
 const (
-	Enum2One   Enum2 = "One"
+	Enum2Four  Enum2 = "Four"
 	Enum2Three Enum2 = "Three"
 	Enum2Two   Enum2 = "Two"
 )
@@ -46,9 +38,33 @@ const (
 
 // Defines values for Enum5.
 const (
-	N5 Enum5 = 5
-	N6 Enum5 = 6
-	N7 Enum5 = 7
+	Enum5N5 Enum5 = 5
+	Enum5N6 Enum5 = 6
+	Enum5N7 Enum5 = 7
+)
+
+// Defines values for EnumUnion.
+const (
+	EnumUnionFour  EnumUnion = "Four"
+	EnumUnionOne   EnumUnion = "One"
+	EnumUnionThree EnumUnion = "Three"
+	EnumUnionTwo   EnumUnion = "Two"
+)
+
+// Defines values for EnumUnion2.
+const (
+	EnumUnion2One   EnumUnion2 = "One"
+	EnumUnion2Seven EnumUnion2 = "Seven"
+	EnumUnion2Three EnumUnion2 = "Three"
+	EnumUnion2Two   EnumUnion2 = "Two"
+)
+
+// Defines values for FunnyValues.
+const (
+	FunnyValuesAnd      FunnyValues = "&"
+	FunnyValuesAsterisk FunnyValues = "*"
+	FunnyValuesEmpty    FunnyValues = ""
+	FunnyValuesN5       FunnyValues = "5"
 )
 
 // Defines values for EnumParam1.
@@ -128,6 +144,15 @@ type Enum4 string
 // Numerical enum
 type Enum5 int
 
+// EnumUnion defines model for EnumUnion.
+type EnumUnion string
+
+// EnumUnion2 defines model for EnumUnion2.
+type EnumUnion2 string
+
+// Edge cases for enum names
+type FunnyValues string
+
 // ObjectWithJsonField defines model for ObjectWithJsonField.
 type ObjectWithJsonField struct {
 	Name   string          `json:"name"`
@@ -135,6 +160,18 @@ type ObjectWithJsonField struct {
 	Value2 json.RawMessage `json:"value2,omitempty"`
 }
 
+// When a Schema is renamed, $ref should refer to the new name
+type ReferenceToRenameMe struct {
+	// This schema should be renamed via x-go-name when generating
+	NewName NewName `json:"ToNewName"`
+}
+
+// This schema should be renamed via x-go-name when generating
+type NewName struct {
+	Prop1 string `json:"prop1"`
+	Prop2 string `json:"prop2"`
+}
+
 // SchemaObject defines model for SchemaObject.
 type SchemaObject struct {
 	FirstName string `json:"firstName"`
@@ -156,15 +193,15 @@ type EnumParam2 string
 type EnumParam3 string
 
 // a parameter
-type ParameterObject string
+type RenamedParameterObject string
 
-// ResponseObject defines model for ResponseObject.
-type ResponseObject struct {
+// RenamedResponseObject defines model for ResponseObject.
+type RenamedResponseObject struct {
 	Field SchemaObject `json:"Field"`
 }
 
-// RequestBody defines model for RequestBody.
-type RequestBody struct {
+// RenamedRequestBody defines model for RequestBody.
+type RenamedRequestBody struct {
 	Field SchemaObject `json:"Field"`
 }
 
@@ -203,7 +240,7 @@ type BodyWithAddPropsJSONBody_Inner struct {
 }
 
 // EnsureEverythingIsReferencedJSONRequestBody defines body for EnsureEverythingIsReferenced for application/json ContentType.
-type EnsureEverythingIsReferencedJSONRequestBody RequestBody
+type EnsureEverythingIsReferencedJSONRequestBody RenamedRequestBody
 
 // BodyWithAddPropsJSONRequestBody defines body for BodyWithAddProps for application/json ContentType.
 type BodyWithAddPropsJSONRequestBody BodyWithAddPropsJSONBody
@@ -803,103 +840,3 @@ func (a AdditionalPropertiesObject5) MarshalJSON() ([]byte, error) {
 	}
 	return json.Marshal(object)
 }
-
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
-
-	"H4sIAAAAAAAC/9xYW2/bOhL+KwPuPrJx4rS7gN/SG7YL9II2wHmog4IWRxF7ZFIlKbtG4f9+MKRsyRLl",
-	"Ok5R4JyXxJbJmW9u38zoB8vMsjIatXds9oNVwoolerTh2ytdLz/Qkyv6JtFlVlVeGc1mTMD+LONM0aNv",
-	"NdoN40yLJbIZCzdJxBXjzGUFLgWJQV0v2eyztzXyXJQOOVsYX7A7zvymoovOW6Xv2XbLWwTTRyGY/gIE",
-	"149CcJ1CwESpMmSc4Yr+LswijeHDTsv7xVfMPEnIjPaow0dRVaXKBGGafHUE7EdHVWVNhdYrDBF9rbCU",
-	"9OHfFnM2Y/+atPGfxEtu8in8b3SRfovfamVREuQo4Y4ee/zuJ1UpVE9l34AtP89vHYt3KND550Y2xnzc",
-	"P9j87VwSZbjKaLczJn75h4T4BpxaViXCzkgwrbIGBQm6kVLRFVF+2FsRYQXOEYmfO/qV9niPlg3U/084",
-	"aO9C6yEwOdBlUNoz3nOdkmnZMSkHVnNmqqgg5ZJDnwYRnDS0Fb7zCD/ihem4FxrqOjT8pUEH2ngQZWnW",
-	"aR881u5fZNr1uGmBmvsZRQY5EHqTsGozsOkB2B8G++nDYIdM1EZvlqZ2kFNpwbpQWQHFWI4O46M12p+p",
-	"/aXmn3Y94uLnePHZseo+nblOr/u18gVEIZAbC1Jl4ZCNDh9Aj4PLoOW/MDovVeYbgWG44ED9HFairKn4",
-	"ECV4AwuEymKuvqOMZ0nFXJOvLuaamn4zBLzXVD63a0N/C4uYGAIinulJeK5+G57ESPSqozlrsLXQHIiF",
-	"WSFPgZrrPSoYggqGRWSvDSF7LuworqdDXO/MHo6DAi1ycIWpSwmFWCHUemmkyhXK4Dt3oPuFoFbx0twz",
-	"zt6a2o075FlCcb1EqzJRBsFduc/4f/h/W0kd3o3Z/Yfyxf+d0fuGflKFcxa8H1I3N3YpPJuxMDPwkaPT",
-	"E46mKb/RlKr8gzIdYM+Vdf7dmAEWhXyvy83HRiORw9Cxt4Vye/oH5WAHEISWsJPBwRnwBcK9gaWRWB6E",
-	"XXkgwoDKkPcth7kWjp6uVVmGNrqgSSEra0lVU6CmH5UDh9pDbs0SslLRZ2/AoV2hjWm7U78j56GNpkwb",
-	"v7bKY8r6Xpp0TkYl/RgFDbzj6hHHjqm8C1Od0rkh7bSoaIdt4rG3b24Jr1eeLGG36Dx8Ci6gzEDrYpiu",
-	"Li4vLuOshFpUis3Y9cXlBe2ElfBFSIcJaldbfIIrtBtfKH3/RLknFnO0qDMMyX+PfiQHUMsQP8DvynkX",
-	"Ay48tM0DMqEpkplF4VGC0uAL5ebaVZiFdGlCXdlaExOxANeGgfuNDLRGAF/t8b1xH1t03dVkM9a/DraX",
-	"SXd16W8C08vLR4z/uVrhz3rosba85Sw3tT1fxFMS8bXLW8fkpKiOkkU/woirkJehc50t4zrIWJvzJUwD",
-	"a/aIcbgoVaXIsDCl3K0xuahLP55FTaJMevti3CgnYa92X6iTfhFSfqHccKPlcwNUgrE9t29+QkEIWBi5",
-	"aSbVhlbSk1WiWsL27iioNzKQSRhpO6+WPqfJfHdifDQOylIvDKor1qW/yLptjRwbnAe9y/lNoLS4wbIt",
-	"PwWt7kz5YS5ue1N0Io08Ls48c+1rqwMReUPtJ5yMow/Npim0dHNt7J/jHpge9cCDNopEX+oncmoTuNtu",
-	"73pk1snnDqGd/VrhoFro58q4RGKHNQAayu1mMmEQStOvUlnMfNLXnEpgro/GlGomdTdRDsTyvWKwZ766",
-	"On0BPDXCnbHzzC1wt//vUmDbT8Ptb82J7Xb7VwAAAP//Ati2mNYWAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
-func decodeSpec() ([]byte, error) {
-	zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
-	if err != nil {
-		return nil, fmt.Errorf("error base64 decoding spec: %s", err)
-	}
-	zr, err := gzip.NewReader(bytes.NewReader(zipped))
-	if err != nil {
-		return nil, fmt.Errorf("error decompressing spec: %s", err)
-	}
-	var buf bytes.Buffer
-	_, err = buf.ReadFrom(zr)
-	if err != nil {
-		return nil, fmt.Errorf("error decompressing spec: %s", err)
-	}
-
-	return buf.Bytes(), nil
-}
-
-var rawSpec = decodeSpecCached()
-
-// a naive cached of a decoded swagger spec
-func decodeSpecCached() func() ([]byte, error) {
-	data, err := decodeSpec()
-	return func() ([]byte, error) {
-		return data, err
-	}
-}
-
-// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
-func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
-	var res = make(map[string]func() ([]byte, error))
-	if len(pathToFile) > 0 {
-		res[pathToFile] = rawSpec
-	}
-
-	return res
-}
-
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
-	var resolvePath = PathToRawSpec("")
-
-	loader := openapi3.NewLoader()
-	loader.IsExternalRefsAllowed = true
-	loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
-		var pathToFile = url.String()
-		pathToFile = path.Clean(pathToFile)
-		getSpec, ok := resolvePath[pathToFile]
-		if !ok {
-			err1 := fmt.Errorf("path not found: %s", pathToFile)
-			return nil, err1
-		}
-		return getSpec()
-	}
-	var specData []byte
-	specData, err = rawSpec()
-	if err != nil {
-		return
-	}
-	swagger, err = loader.LoadFromData(specData)
-	if err != nil {
-		return
-	}
-	return
-}
diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml
index 4ec1f1b..a11eb9f 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -195,7 +195,7 @@ components:
         Conflicts with Enum1, enum values need to be prefixed with type
         name.
       type: string
-      enum: [ One, Two, Three ]
+      enum: [ Two, Three, Four ]
     Enum3:
       description: |
         Enum values conflict with Enums above, need to be prefixed
@@ -212,8 +212,46 @@ components:
         Numerical enum
       type: integer
       enum: [ 5, 6, 7 ]
+    EnumUnion:
+      description: |
+        Two enums of the same type combined with allOf.
+      allOf:
+        - $ref: "#/components/schemas/Enum1"
+        - $ref: "#/components/schemas/Enum2"
+    EnumUnion2:
+      description: |
+        Two enums of the same type combined with allOf.
+      allOf:
+      - $ref: "#/components/schemas/Enum1"
+      - enum: [ Seven ]
+    FunnyValues:
+      description: Edge cases for enum names
+      type: string
+      enum:
+        - '*'
+        - '5'
+        - '&'
+        - ''
+    RenameMe:
+      description: This schema should be renamed via x-go-name when generating
+      x-go-name: NewName
+      type: object
+      properties:
+        prop1:
+          type: string
+        prop2:
+          type: string
+      required: [prop1, prop2]
+    ReferenceToRenameMe:
+      description: When a Schema is renamed, $ref should refer to the new name
+      type: object
+      properties:
+        ToNewName:
+          $ref: "#/components/schemas/RenameMe"
+      required: [ToNewName]
   responses:
     ResponseObject:
+      x-go-name: RenamedResponseObject
       description: A simple response object
       content:
         application/json:
@@ -227,6 +265,7 @@ components:
             type: string
   parameters:
     ParameterObject:
+      x-go-name: RenamedParameterObject
       name: ParameterObject
       description: a parameter
       in: query
@@ -263,6 +302,7 @@ components:
         enum: [ alice, eve, bob ]
   requestBodies:
     RequestBody:
+      x-go-name: RenamedRequestBody
       content:
         application/json:
           schema:
diff --git a/internal/test/components/config.yaml b/internal/test/components/config.yaml
index 1dc3d1e..bd3484a 100644
--- a/internal/test/components/config.yaml
+++ b/internal/test/components/config.yaml
@@ -4,4 +4,3 @@ package: components
 generate:
   - types
   - skip-prune
-  - spec
diff --git a/internal/test/components/doc.go b/internal/test/components/doc.go
index 18291c8..651d172 100644
--- a/internal/test/components/doc.go
+++ b/internal/test/components/doc.go
@@ -1,3 +1,3 @@
 package components
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen  --config=config.yaml components.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style  --config=config.yaml components.yaml
diff --git a/internal/test/externalref/externalref.cfg.yaml b/internal/test/externalref/externalref.cfg.yaml
index 82fe596..caab32e 100644
--- a/internal/test/externalref/externalref.cfg.yaml
+++ b/internal/test/externalref/externalref.cfg.yaml
@@ -1,10 +1,11 @@
-output:
-  externalref.gen.go
 package: externalref
 generate:
-  - types
-  - skip-prune
-  - spec
+  models: true
+  embedded-spec: true
 import-mapping:
   ./packageA/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageA
   ./packageB/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageB
+output: externalref.gen.go
+output-options:
+
+  skip-prune: true
diff --git a/internal/test/externalref/packageA/doc.go b/internal/test/externalref/packageA/doc.go
index 6d851c8..cce4462 100644
--- a/internal/test/externalref/packageA/doc.go
+++ b/internal/test/externalref/packageA/doc.go
@@ -1,3 +1,3 @@
 package packageA
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -generate types,skip-prune,spec --package=packageA -o externalref.gen.go --import-mapping=../packageB/spec.yaml:github.com/deepmap/oapi-codegen/internal/test/externalref/packageB spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style -generate types,skip-prune,spec --package=packageA -o externalref.gen.go --import-mapping=../packageB/spec.yaml:github.com/deepmap/oapi-codegen/internal/test/externalref/packageB spec.yaml
diff --git a/internal/test/externalref/packageB/doc.go b/internal/test/externalref/packageB/doc.go
index 29c3185..c03650a 100644
--- a/internal/test/externalref/packageB/doc.go
+++ b/internal/test/externalref/packageB/doc.go
@@ -1,3 +1,3 @@
 package packageB
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -generate types,skip-prune,spec --package=packageB -o externalref.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style -generate types,skip-prune,spec --package=packageB -o externalref.gen.go spec.yaml
diff --git a/internal/test/issues/issue-312/doc.go b/internal/test/issues/issue-312/doc.go
index de380e3..bc971d5 100644
--- a/internal/test/issues/issue-312/doc.go
+++ b/internal/test/issues/issue-312/doc.go
@@ -1,3 +1,3 @@
 package issue_312
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=issue_312 -o issue.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=issue_312 -o issue.gen.go spec.yaml
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index 4710f7c..480b03d 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -44,10 +44,10 @@ type PetNames struct {
 }
 
 // ValidatePetsJSONBody defines parameters for ValidatePets.
-type ValidatePetsJSONBody PetNames
+type ValidatePetsJSONBody = PetNames
 
 // ValidatePetsJSONRequestBody defines body for ValidatePets for application/json ContentType.
-type ValidatePetsJSONRequestBody ValidatePetsJSONBody
+type ValidatePetsJSONRequestBody = ValidatePetsJSONBody
 
 // RequestEditorFn  is the function signature for the RequestEditor callback function
 type RequestEditorFn func(ctx context.Context, req *http.Request) error
diff --git a/internal/test/issues/issue-312/spec.yaml b/internal/test/issues/issue-312/spec.yaml
index bcf273e..47be65f 100644
--- a/internal/test/issues/issue-312/spec.yaml
+++ b/internal/test/issues/issue-312/spec.yaml
@@ -1,4 +1,3 @@
-
 openapi: "3.0.0"
 info:
   version: 1.0.0
diff --git a/internal/test/issues/issue-52/doc.go b/internal/test/issues/issue-52/doc.go
index 1d25700..9dfe7fb 100644
--- a/internal/test/issues/issue-52/doc.go
+++ b/internal/test/issues/issue-52/doc.go
@@ -1,3 +1,3 @@
 package issue_52
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen  --package=issue_52 -o issue.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style  --package=issue_52 -o issue.gen.go spec.yaml
diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index f671f94..dd162db 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -21,7 +21,7 @@ import (
 )
 
 // ArrayValue defines model for ArrayValue.
-type ArrayValue []Value
+type ArrayValue = []Value
 
 // Document defines model for Document.
 type Document struct {
diff --git a/internal/test/issues/issue-52/issue_test.go b/internal/test/issues/issue-52/issue_test.go
index 0408fe6..960c266 100644
--- a/internal/test/issues/issue-52/issue_test.go
+++ b/internal/test/issues/issue-52/issue_test.go
@@ -17,13 +17,16 @@ func TestIssue(t *testing.T) {
 	swagger, err := openapi3.NewLoader().LoadFromData(spec)
 	require.NoError(t, err)
 
-	opts := codegen.Options{
-		GenerateClient:     true,
-		GenerateEchoServer: true,
-		GenerateTypes:      true,
-		EmbedSpec:          true,
+	opts := codegen.Configuration{
+		PackageName: "issue_52",
+		Generate: codegen.GenerateOptions{
+			EchoServer:   true,
+			Client:       true,
+			Models:       true,
+			EmbeddedSpec: true,
+		},
 	}
 
-	_, err = codegen.Generate(swagger, "issue_52", opts)
+	_, err = codegen.Generate(swagger, opts)
 	require.NoError(t, err)
 }
diff --git a/internal/test/issues/issue-579/gen.go b/internal/test/issues/issue-579/gen.go
new file mode 100644
index 0000000..8a79e37
--- /dev/null
+++ b/internal/test/issues/issue-579/gen.go
@@ -0,0 +1,3 @@
+package issue_579
+
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=issue_579 --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
new file mode 100644
index 0000000..93cc60a
--- /dev/null
+++ b/internal/test/issues/issue-579/issue.gen.go
@@ -0,0 +1,17 @@
+// Package issue_579 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
+
+import (
+	openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
+)
+
+// AliasedDate defines model for AliasedDate.
+type AliasedDate = openapi_types.Date
+
+// Pet defines model for Pet.
+type Pet struct {
+	Born   *AliasedDate        `json:"born,omitempty"`
+	BornAt *openapi_types.Date `json:"born_at,omitempty"`
+}
diff --git a/internal/test/issues/issue-579/issue_test.go b/internal/test/issues/issue-579/issue_test.go
new file mode 100644
index 0000000..4c1b901
--- /dev/null
+++ b/internal/test/issues/issue-579/issue_test.go
@@ -0,0 +1,14 @@
+package issue_579
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestAliasedDate(t *testing.T) {
+	pet := Pet{}
+	err := json.Unmarshal([]byte(`{"born": "2022-05-19", "born_at": "2022-05-20"}`), &pet)
+	require.NoError(t, err)
+}
diff --git a/internal/test/issues/issue-579/spec.yaml b/internal/test/issues/issue-579/spec.yaml
new file mode 100644
index 0000000..2bf359c
--- /dev/null
+++ b/internal/test/issues/issue-579/spec.yaml
@@ -0,0 +1,27 @@
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: Issue 579 test
+paths:
+  /placeholder:
+    get:
+      responses:
+        200:
+          description: placeholder
+          content:
+            text/plain:
+              schema:
+                type: string
+components:
+  schemas:
+    Pet:
+      type: object
+      properties:
+        born:
+          $ref: "#/components/schemas/AliasedDate"
+        born_at:
+          type: string
+          format: date
+    AliasedDate:
+      type: string
+      format: date
diff --git a/internal/test/issues/issue-grab_import_names/doc.go b/internal/test/issues/issue-grab_import_names/doc.go
index 2f8ae67..7bf6678 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
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen  --package=grab_import_names -o issue.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style  --package=grab_import_names -o issue.gen.go spec.yaml
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 705ae82..1f90f83 100644
--- a/internal/test/issues/issue-grab_import_names/issue_test.go
+++ b/internal/test/issues/issue-grab_import_names/issue_test.go
@@ -3,23 +3,27 @@ package grab_import_names
 import (
 	"testing"
 
-	"github.com/deepmap/oapi-codegen/pkg/codegen"
 	"github.com/getkin/kin-openapi/openapi3"
 	"github.com/stretchr/testify/require"
+
+	"github.com/deepmap/oapi-codegen/pkg/codegen"
 )
 
 func TestLineComments(t *testing.T) {
 	swagger, err := openapi3.NewLoader().LoadFromFile("spec.yaml")
 	require.NoError(t, err)
 
-	opts := codegen.Options{
-		GenerateClient:     true,
-		GenerateEchoServer: true,
-		GenerateTypes:      true,
-		EmbedSpec:          true,
+	opts := codegen.Configuration{
+		PackageName: "grab_import_names",
+		Generate: codegen.GenerateOptions{
+			EchoServer:   true,
+			Client:       true,
+			Models:       true,
+			EmbeddedSpec: true,
+		},
 	}
 
-	code, err := codegen.Generate(swagger, "grab_import_names", opts)
+	code, err := codegen.Generate(swagger, opts)
 	require.NoError(t, err)
 	require.NotContains(t, code, `"openapi_types"`)
 }
diff --git a/internal/test/issues/issue-illegal_enum_names/doc.go b/internal/test/issues/issue-illegal_enum_names/doc.go
index b348a97..7d1b2f1 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
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen  --package=illegal_enum_names -o issue.gen.go spec.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style  --package=illegal_enum_names -o issue.gen.go spec.yaml
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 1032cb0..8c40e09 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue_test.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go
@@ -6,23 +6,27 @@ import (
 	"go/token"
 	"testing"
 
-	"github.com/deepmap/oapi-codegen/pkg/codegen"
 	"github.com/getkin/kin-openapi/openapi3"
 	"github.com/stretchr/testify/require"
+
+	"github.com/deepmap/oapi-codegen/pkg/codegen"
 )
 
 func TestIllegalEnumNames(t *testing.T) {
 	swagger, err := openapi3.NewLoader().LoadFromFile("spec.yaml")
 	require.NoError(t, err)
 
-	opts := codegen.Options{
-		GenerateClient:     true,
-		GenerateEchoServer: true,
-		GenerateTypes:      true,
-		EmbedSpec:          true,
+	opts := codegen.Configuration{
+		PackageName: "illegal_enum_names",
+		Generate: codegen.GenerateOptions{
+			EchoServer:   true,
+			Client:       true,
+			Models:       true,
+			EmbeddedSpec: true,
+		},
 	}
 
-	code, err := codegen.Generate(swagger, "illegal_enum_names", opts)
+	code, err := codegen.Generate(swagger, opts)
 	require.NoError(t, err)
 
 	f, err := parser.ParseFile(token.NewFileSet(), "", code, parser.AllErrors)
diff --git a/internal/test/parameters/doc.go b/internal/test/parameters/doc.go
index e4b88fb..736ce1e 100644
--- a/internal/test/parameters/doc.go
+++ b/internal/test/parameters/doc.go
@@ -1,3 +1,3 @@
 package parameters
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=parameters -o parameters.gen.go parameters.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=parameters -o parameters.gen.go parameters.yaml
diff --git a/internal/test/schemas/doc.go b/internal/test/schemas/doc.go
index 81a0936..a794f06 100644
--- a/internal/test/schemas/doc.go
+++ b/internal/test/schemas/doc.go
@@ -1,3 +1,3 @@
 package schemas
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=schemas -o schemas.gen.go schemas.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --package=schemas -o schemas.gen.go schemas.yaml
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index 20ff8cc..e65ba86 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -36,21 +36,21 @@ const (
 )
 
 // This schema name starts with a number
-type N5StartsWithNumber map[string]interface{}
+type N5StartsWithNumber = map[string]interface{}
 
 // AnyType1 defines model for AnyType1.
-type AnyType1 interface{}
+type AnyType1 = interface{}
 
 // AnyType2 represents any type.
 //
 // This should be an interface{}
-type AnyType2 interface{}
+type AnyType2 = interface{}
 
 // CustomStringType defines model for CustomStringType.
-type CustomStringType string
+type CustomStringType = string
 
 // EnumInObjInArray defines model for EnumInObjInArray.
-type EnumInObjInArray []struct {
+type EnumInObjInArray = []struct {
 	Val *EnumInObjInArrayVal `json:"val,omitempty"`
 }
 
@@ -58,7 +58,7 @@ type EnumInObjInArray []struct {
 type EnumInObjInArrayVal string
 
 // GenericObject defines model for GenericObject.
-type GenericObject map[string]interface{}
+type GenericObject = map[string]interface{}
 
 // NullableProperties defines model for NullableProperties.
 type NullableProperties struct {
@@ -69,13 +69,13 @@ type NullableProperties struct {
 }
 
 // StringInPath defines model for StringInPath.
-type StringInPath string
+type StringInPath = string
 
 // Issue185JSONBody defines parameters for Issue185.
-type Issue185JSONBody NullableProperties
+type Issue185JSONBody = NullableProperties
 
 // Issue9JSONBody defines parameters for Issue9.
-type Issue9JSONBody interface{}
+type Issue9JSONBody = interface{}
 
 // Issue9Params defines parameters for Issue9.
 type Issue9Params struct {
@@ -83,10 +83,10 @@ type Issue9Params struct {
 }
 
 // Issue185JSONRequestBody defines body for Issue185 for application/json ContentType.
-type Issue185JSONRequestBody Issue185JSONBody
+type Issue185JSONRequestBody = Issue185JSONBody
 
 // Issue9JSONRequestBody defines body for Issue9 for application/json ContentType.
-type Issue9JSONRequestBody Issue9JSONBody
+type Issue9JSONRequestBody = Issue9JSONBody
 
 // RequestEditorFn  is the function signature for the RequestEditor callback function
 type RequestEditorFn func(ctx context.Context, req *http.Request) error
diff --git a/internal/test/server/doc.go b/internal/test/server/doc.go
index 421ca4d..f3c8230 100644
--- a/internal/test/server/doc.go
+++ b/internal/test/server/doc.go
@@ -1,4 +1,4 @@
 package server
 
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --generate=types,chi-server --package=server -o server.gen.go ../test-schema.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --old-config-style --generate=types,chi-server --package=server -o server.gen.go ../test-schema.yaml
 //go:generate go run github.com/matryer/moq -out server_moq.gen.go . ServerInterface
diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go
index 1f2f059..c9df6ac 100644
--- a/internal/test/server/server.gen.go
+++ b/internal/test/server/server.gen.go
@@ -75,10 +75,10 @@ type SomeObject struct {
 }
 
 // Argument defines model for argument.
-type Argument string
+type Argument = string
 
 // ResponseWithReference defines model for ResponseWithReference.
-type ResponseWithReference SomeObject
+type ResponseWithReference = SomeObject
 
 // SimpleResponse defines model for SimpleResponse.
 type SimpleResponse struct {
@@ -101,10 +101,10 @@ type GetWithArgsParams struct {
 type GetWithContentTypeParamsContentType string
 
 // CreateResourceJSONBody defines parameters for CreateResource.
-type CreateResourceJSONBody EveryTypeRequired
+type CreateResourceJSONBody = EveryTypeRequired
 
 // CreateResource2JSONBody defines parameters for CreateResource2.
-type CreateResource2JSONBody Resource
+type CreateResource2JSONBody = Resource
 
 // CreateResource2Params defines parameters for CreateResource2.
 type CreateResource2Params struct {
@@ -119,10 +119,10 @@ type UpdateResource3JSONBody struct {
 }
 
 // CreateResourceJSONRequestBody defines body for CreateResource for application/json ContentType.
-type CreateResourceJSONRequestBody CreateResourceJSONBody
+type CreateResourceJSONRequestBody = CreateResourceJSONBody
 
 // CreateResource2JSONRequestBody defines body for CreateResource2 for application/json ContentType.
-type CreateResource2JSONRequestBody CreateResource2JSONBody
+type CreateResource2JSONRequestBody = CreateResource2JSONBody
 
 // UpdateResource3JSONRequestBody defines body for UpdateResource3 for application/json ContentType.
 type UpdateResource3JSONRequestBody UpdateResource3JSONBody
@@ -169,36 +169,36 @@ type ServerInterfaceWrapper struct {
 	ErrorHandlerFunc   func(w http.ResponseWriter, r *http.Request, err error)
 }
 
-type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc
+type MiddlewareFunc func(http.Handler) http.Handler
 
 // GetEveryTypeOptional operation middleware
 func (siw *ServerInterfaceWrapper) GetEveryTypeOptional(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetEveryTypeOptional(w, r)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetSimple operation middleware
 func (siw *ServerInterfaceWrapper) GetSimple(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetSimple(w, r)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetWithArgs operation middleware
@@ -256,15 +256,15 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
 
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetWithArgs(w, r, params)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetWithReferences operation middleware
@@ -276,7 +276,7 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
 	// ------------- Path parameter "global_argument" -------------
 	var globalArgument int64
 
-	err = runtime.BindStyledParameter("simple", false, "global_argument", chi.URLParam(r, "global_argument"), &globalArgument)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "global_argument", runtime.ParamLocationPath, chi.URLParam(r, "global_argument"), &globalArgument)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "global_argument", Err: err})
 		return
@@ -285,21 +285,21 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
 	// ------------- Path parameter "argument" -------------
 	var argument Argument
 
-	err = runtime.BindStyledParameter("simple", false, "argument", chi.URLParam(r, "argument"), &argument)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "argument", runtime.ParamLocationPath, chi.URLParam(r, "argument"), &argument)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "argument", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetWithReferences(w, r, globalArgument, argument)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetWithContentType operation middleware
@@ -311,36 +311,36 @@ func (siw *ServerInterfaceWrapper) GetWithContentType(w http.ResponseWriter, r *
 	// ------------- Path parameter "content_type" -------------
 	var contentType GetWithContentTypeParamsContentType
 
-	err = runtime.BindStyledParameter("simple", false, "content_type", chi.URLParam(r, "content_type"), &contentType)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "content_type", runtime.ParamLocationPath, chi.URLParam(r, "content_type"), &contentType)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "content_type", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetWithContentType(w, r, contentType)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetReservedKeyword operation middleware
 func (siw *ServerInterfaceWrapper) GetReservedKeyword(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetReservedKeyword(w, r)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // CreateResource operation middleware
@@ -352,21 +352,21 @@ func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http
 	// ------------- Path parameter "argument" -------------
 	var argument Argument
 
-	err = runtime.BindStyledParameter("simple", false, "argument", chi.URLParam(r, "argument"), &argument)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "argument", runtime.ParamLocationPath, chi.URLParam(r, "argument"), &argument)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "argument", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.CreateResource(w, r, argument)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // CreateResource2 operation middleware
@@ -378,7 +378,7 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
 	// ------------- Path parameter "inline_argument" -------------
 	var inlineArgument int
 
-	err = runtime.BindStyledParameter("simple", false, "inline_argument", chi.URLParam(r, "inline_argument"), &inlineArgument)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "inline_argument", runtime.ParamLocationPath, chi.URLParam(r, "inline_argument"), &inlineArgument)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "inline_argument", Err: err})
 		return
@@ -398,15 +398,15 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.CreateResource2(w, r, inlineArgument, params)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // UpdateResource3 operation middleware
@@ -418,36 +418,36 @@ func (siw *ServerInterfaceWrapper) UpdateResource3(w http.ResponseWriter, r *htt
 	// ------------- Path parameter "fallthrough" -------------
 	var pFallthrough int
 
-	err = runtime.BindStyledParameter("simple", false, "fallthrough", chi.URLParam(r, "fallthrough"), &pFallthrough)
+	err = runtime.BindStyledParameterWithLocation("simple", false, "fallthrough", runtime.ParamLocationPath, chi.URLParam(r, "fallthrough"), &pFallthrough)
 	if err != nil {
 		siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "fallthrough", Err: err})
 		return
 	}
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.UpdateResource3(w, r, pFallthrough)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 // GetResponseWithReference operation middleware
 func (siw *ServerInterfaceWrapper) GetResponseWithReference(w http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 
-	var handler = func(w http.ResponseWriter, r *http.Request) {
+	var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		siw.Handler.GetResponseWithReference(w, r)
-	}
+	})
 
 	for _, middleware := range siw.HandlerMiddlewares {
 		handler = middleware(handler)
 	}
 
-	handler(w, r.WithContext(ctx))
+	handler.ServeHTTP(w, r.WithContext(ctx))
 }
 
 type UnescapedCookieParamError struct {
diff --git a/internal/test/server/server_moq.gen.go b/internal/test/server/server_moq.gen.go
index b4dde63..aa22e65 100644
--- a/internal/test/server/server_moq.gen.go
+++ b/internal/test/server/server_moq.gen.go
@@ -18,7 +18,7 @@ var _ ServerInterface = &ServerInterfaceMock{}
 //
 // 		// make and configure a mocked ServerInterface
 // 		mockedServerInterface := &ServerInterfaceMock{
-// 			CreateResourceFunc: func(w http.ResponseWriter, r *http.Request, argument Argument)  {
+// 			CreateResourceFunc: func(w http.ResponseWriter, r *http.Request, argument string)  {
 // 				panic("mock out the CreateResource method")
 // 			},
 // 			CreateResource2Func: func(w http.ResponseWriter, r *http.Request, inlineArgument int, params CreateResource2Params)  {
@@ -42,7 +42,7 @@ var _ ServerInterface = &ServerInterfaceMock{}
 // 			GetWithContentTypeFunc: func(w http.ResponseWriter, r *http.Request, contentType GetWithContentTypeParamsContentType)  {
 // 				panic("mock out the GetWithContentType method")
 // 			},
-// 			GetWithReferencesFunc: func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument Argument)  {
+// 			GetWithReferencesFunc: func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument string)  {
 // 				panic("mock out the GetWithReferences method")
 // 			},
 // 			UpdateResource3Func: func(w http.ResponseWriter, r *http.Request, pFallthrough int)  {
@@ -56,7 +56,7 @@ var _ ServerInterface = &ServerInterfaceMock{}
 // 	}
 type ServerInterfaceMock struct {
 	// CreateResourceFunc mocks the CreateResource method.
-	CreateResourceFunc func(w http.ResponseWriter, r *http.Request, argument Argument)
+	CreateResourceFunc func(w http.ResponseWriter, r *http.Request, argument string)
 
 	// CreateResource2Func mocks the CreateResource2 method.
 	CreateResource2Func func(w http.ResponseWriter, r *http.Request, inlineArgument int, params CreateResource2Params)
@@ -80,7 +80,7 @@ type ServerInterfaceMock struct {
 	GetWithContentTypeFunc func(w http.ResponseWriter, r *http.Request, contentType GetWithContentTypeParamsContentType)
 
 	// GetWithReferencesFunc mocks the GetWithReferences method.
-	GetWithReferencesFunc func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument Argument)
+	GetWithReferencesFunc func(w http.ResponseWriter, r *http.Request, globalArgument int64, argument string)
 
 	// UpdateResource3Func mocks the UpdateResource3 method.
 	UpdateResource3Func func(w http.ResponseWriter, r *http.Request, pFallthrough int)
@@ -94,7 +94,7 @@ type ServerInterfaceMock struct {
 			// R is the r argument value.
 			R *http.Request
 			// Argument is the argument argument value.
-			Argument Argument
+			Argument string
 		}
 		// CreateResource2 holds details about calls to the CreateResource2 method.
 		CreateResource2 []struct {
@@ -162,7 +162,7 @@ type ServerInterfaceMock struct {
 			// GlobalArgument is the globalArgument argument value.
 			GlobalArgument int64
 			// Argument is the argument argument value.
-			Argument Argument
+			Argument string
 		}
 		// UpdateResource3 holds details about calls to the UpdateResource3 method.
 		UpdateResource3 []struct {
@@ -187,14 +187,14 @@ type ServerInterfaceMock struct {
 }
 
 // CreateResource calls CreateResourceFunc.
-func (mock *ServerInterfaceMock) CreateResource(w http.ResponseWriter, r *http.Request, argument Argument) {
+func (mock *ServerInterfaceMock) CreateResource(w http.ResponseWriter, r *http.Request, argument string) {
 	if mock.CreateResourceFunc == nil {
 		panic("ServerInterfaceMock.CreateResourceFunc: method is nil but ServerInterface.CreateResource was just called")
 	}
 	callInfo := struct {
 		W        http.ResponseWriter
 		R        *http.Request
-		Argument Argument
+		Argument string
 	}{
 		W:        w,
 		R:        r,
@@ -212,12 +212,12 @@ func (mock *ServerInterfaceMock) CreateResource(w http.ResponseWriter, r *http.R
 func (mock *ServerInterfaceMock) CreateResourceCalls() []struct {
 	W        http.ResponseWriter
 	R        *http.Request
-	Argument Argument
+	Argument string
 } {
 	var calls []struct {
 		W        http.ResponseWriter
 		R        *http.Request
-		Argument Argument
+		Argument string
 	}
 	mock.lockCreateResource.RLock()
 	calls = mock.calls.CreateResource
@@ -487,7 +487,7 @@ func (mock *ServerInterfaceMock) GetWithContentTypeCalls() []struct {
 }
 
 // GetWithReferences calls GetWithReferencesFunc.
-func (mock *ServerInterfaceMock) GetWithReferences(w http.ResponseWriter, r *http.Request, globalArgument int64, argument Argument) {
+func (mock *ServerInterfaceMock) GetWithReferences(w http.ResponseWriter, r *http.Request, globalArgument int64, argument string) {
 	if mock.GetWithReferencesFunc == nil {
 		panic("ServerInterfaceMock.GetWithReferencesFunc: method is nil but ServerInterface.GetWithReferences was just called")
 	}
@@ -495,7 +495,7 @@ func (mock *ServerInterfaceMock) GetWithReferences(w http.ResponseWriter, r *htt
 		W              http.ResponseWriter
 		R              *http.Request
 		GlobalArgument int64
-		Argument       Argument
+		Argument       string
 	}{
 		W:              w,
 		R:              r,
@@ -515,13 +515,13 @@ func (mock *ServerInterfaceMock) GetWithReferencesCalls() []struct {
 	W              http.ResponseWriter
 	R              *http.Request
 	GlobalArgument int64
-	Argument       Argument
+	Argument       string
 } {
 	var calls []struct {
 		W              http.ResponseWriter
 		R              *http.Request
 		GlobalArgument int64
-		Argument       Argument
+		Argument       string
 	}
 	mock.lockGetWithReferences.RLock()
 	calls = mock.calls.GetWithReferences
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index be032e0..8d333a6 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -20,11 +20,14 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
 
 	// Input vars for code generation:
 	packageName := "api"
-	opts := Options{
-		GenerateClient:     true,
-		GenerateEchoServer: true,
-		GenerateTypes:      true,
-		EmbedSpec:          true,
+	opts := Configuration{
+		PackageName: packageName,
+		Generate: GenerateOptions{
+			EchoServer:   true,
+			Client:       true,
+			Models:       true,
+			EmbeddedSpec: true,
+		},
 	}
 
 	// Get a spec from the example PetStore definition:
@@ -32,7 +35,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
 	assert.NoError(t, err)
 
 	// Run our code generation:
-	code, err := Generate(swagger, packageName, opts)
+	code, err := Generate(swagger, opts)
 	assert.NoError(t, err)
 	assert.NotEmpty(t, code)
 
@@ -67,9 +70,14 @@ func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
 
 	// Input vars for code generation:
 	packageName := "api"
-	opts := Options{
-		GenerateTypes: true,
-		UserTemplates: userTemplates,
+	opts := Configuration{
+		PackageName: packageName,
+		Generate: GenerateOptions{
+			Models: true,
+		},
+		OutputOptions: OutputOptions{
+			UserTemplates: userTemplates,
+		},
 	}
 
 	// Get a spec from the example PetStore definition:
@@ -77,7 +85,7 @@ func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
 	assert.NoError(t, err)
 
 	// Run our code generation:
-	code, err := Generate(swagger, packageName, opts)
+	code, err := Generate(swagger, opts)
 	assert.NoError(t, err)
 	assert.NotEmpty(t, code)
 
@@ -116,11 +124,14 @@ func TestExampleOpenAPICodeGeneration(t *testing.T) {
 
 	// Input vars for code generation:
 	packageName := "testswagger"
-	opts := Options{
-		GenerateClient:     true,
-		GenerateEchoServer: true,
-		GenerateTypes:      true,
-		EmbedSpec:          true,
+	opts := Configuration{
+		PackageName: packageName,
+		Generate: GenerateOptions{
+			EchoServer:   true,
+			Client:       true,
+			Models:       true,
+			EmbeddedSpec: true,
+		},
 	}
 
 	// Get a spec from the test definition in this file:
@@ -128,7 +139,7 @@ func TestExampleOpenAPICodeGeneration(t *testing.T) {
 	assert.NoError(t, err)
 
 	// Run our code generation:
-	code, err := Generate(swagger, packageName, opts)
+	code, err := Generate(swagger, opts)
 	assert.NoError(t, err)
 	assert.NotEmpty(t, code)
 
diff --git a/pkg/codegen/filter_test.go b/pkg/codegen/filter_test.go
index 1342493..d3a5aec 100644
--- a/pkg/codegen/filter_test.go
+++ b/pkg/codegen/filter_test.go
@@ -10,12 +10,17 @@ import (
 func TestFilterOperationsByTag(t *testing.T) {
 	packageName := "testswagger"
 	t.Run("include tags", func(t *testing.T) {
-		opts := Options{
-			GenerateClient:     true,
-			GenerateEchoServer: true,
-			GenerateTypes:      true,
-			EmbedSpec:          true,
-			IncludeTags:        []string{"hippo", "giraffe", "cat"},
+		opts := Configuration{
+			PackageName: packageName,
+			Generate: GenerateOptions{
+				EchoServer:   true,
+				Client:       true,
+				Models:       true,
+				EmbeddedSpec: true,
+			},
+			OutputOptions: OutputOptions{
+				IncludeTags: []string{"hippo", "giraffe", "cat"},
+			},
 		}
 
 		// Get a spec from the test definition in this file:
@@ -23,7 +28,7 @@ func TestFilterOperationsByTag(t *testing.T) {
 		assert.NoError(t, err)
 
 		// Run our code generation:
-		code, err := Generate(swagger, packageName, opts)
+		code, err := Generate(swagger, opts)
 		assert.NoError(t, err)
 		assert.NotEmpty(t, code)
 		assert.NotContains(t, code, `"/test/:name"`)
@@ -31,12 +36,17 @@ func TestFilterOperationsByTag(t *testing.T) {
 	})
 
 	t.Run("exclude tags", func(t *testing.T) {
-		opts := Options{
-			GenerateClient:     true,
-			GenerateEchoServer: true,
-			GenerateTypes:      true,
-			EmbedSpec:          true,
-			ExcludeTags:        []string{"hippo", "giraffe", "cat"},
+		opts := Configuration{
+			PackageName: packageName,
+			Generate: GenerateOptions{
+				EchoServer:   true,
+				Client:       true,
+				Models:       true,
+				EmbeddedSpec: true,
+			},
+			OutputOptions: OutputOptions{
+				ExcludeTags: []string{"hippo", "giraffe", "cat"},
+			},
 		}
 
 		// Get a spec from the test definition in this file:
@@ -44,7 +54,7 @@ func TestFilterOperationsByTag(t *testing.T) {
 		assert.NoError(t, err)
 
 		// Run our code generation:
-		code, err := Generate(swagger, packageName, opts)
+		code, err := Generate(swagger, opts)
 		assert.NoError(t, err)
 		assert.NotEmpty(t, code)
 		assert.Contains(t, code, `"/test/:name"`)
diff --git a/pkg/codegen/prune_test.go b/pkg/codegen/prune_test.go
index 86437c2..e0cc16c 100644
--- a/pkg/codegen/prune_test.go
+++ b/pkg/codegen/prune_test.go
@@ -18,8 +18,10 @@ func TestFindReferences(t *testing.T) {
 	t.Run("only cat", func(t *testing.T) {
 		swagger, err := openapi3.NewLoader().LoadFromData([]byte(pruneSpecTestFixture))
 		assert.NoError(t, err)
-		opts := Options{
-			IncludeTags: []string{"cat"},
+		opts := Configuration{
+			OutputOptions: OutputOptions{
+				IncludeTags: []string{"cat"},
+			},
 		}
 
 		filterOperationsByTag(swagger, opts)
@@ -31,8 +33,10 @@ func TestFindReferences(t *testing.T) {
 		swagger, err := openapi3.NewLoader().LoadFromData([]byte(pruneSpecTestFixture))
 		assert.NoError(t, err)
 
-		opts := Options{
-			IncludeTags: []string{"dog"},
+		opts := Configuration{
+			OutputOptions: OutputOptions{
+				IncludeTags: []string{"dog"},
+			},
 		}
 
 		filterOperationsByTag(swagger, opts)
@@ -47,8 +51,10 @@ func TestFilterOnlyCat(t *testing.T) {
 	swagger, err := openapi3.NewLoader().LoadFromData([]byte(pruneSpecTestFixture))
 	assert.NoError(t, err)
 
-	opts := Options{
-		IncludeTags: []string{"cat"},
+	opts := Configuration{
+		OutputOptions: OutputOptions{
+			IncludeTags: []string{"cat"},
+		},
 	}
 
 	refs := findComponentRefs(swagger)
@@ -75,8 +81,10 @@ func TestFilterOnlyDog(t *testing.T) {
 	swagger, err := openapi3.NewLoader().LoadFromData([]byte(pruneSpecTestFixture))
 	assert.NoError(t, err)
 
-	opts := Options{
-		IncludeTags: []string{"dog"},
+	opts := Configuration{
+		OutputOptions: OutputOptions{
+			IncludeTags: []string{"dog"},
+		},
 	}
 
 	refs := findComponentRefs(swagger)
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index b391852..0b13ee8 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -263,6 +263,23 @@ func TestSwaggerUriToGinUri(t *testing.T) {
 	assert.Equal(t, "/path/:arg/foo", SwaggerUriToGinUri("/path/{?arg*}/foo"))
 }
 
+func TestSwaggerUriToGorillaUri(t *testing.T) { // TODO
+	assert.Equal(t, "/path", SwaggerUriToGorillaUri("/path"))
+	assert.Equal(t, "/path/{arg}", SwaggerUriToGorillaUri("/path/{arg}"))
+	assert.Equal(t, "/path/{arg1}/{arg2}", SwaggerUriToGorillaUri("/path/{arg1}/{arg2}"))
+	assert.Equal(t, "/path/{arg1}/{arg2}/foo", SwaggerUriToGorillaUri("/path/{arg1}/{arg2}/foo"))
+
+	// Make sure all the exploded and alternate formats match too
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{arg}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{arg*}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{.arg}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{.arg*}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{;arg}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{;arg*}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{?arg}/foo"))
+	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{?arg*}/foo"))
+}
+
 func TestOrderedParamsFromUri(t *testing.T) {
 	result := OrderedParamsFromUri("/path/{param1}/{.param2}/{;param3*}/foo")
 	assert.EqualValues(t, []string{"param1", "param2", "param3"}, result)