Repository: deepmap/oapi-codegen
Pull request #1069 (2023-05-30 14:15:39)

Spell "marshal" and "unmarshal" consistently
This PR modifies comments, errors, and variables to use the spelling for `marshal/unmarshal` with a single `l`. This is because of spelling choices for Go https://github.com/golang/go/wiki/Spelling:

> use marshaling, marshaled etc (single ell). See https://go.dev/cl/33017



Patch:
diff --git a/README.md b/README.md
index 467ce1f..3ef3cdc 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,8 @@ you can focus on implementing the business logic for your service.
 
 We have chosen to focus on [Echo](https://github.com/labstack/echo) as
 our default HTTP routing engine, due to its speed and simplicity for the generated
-stubs, and [Chi](https://github.com/go-chi/chi), and [Gin](https://github.com/gin-gonic/gin)
+stubs. [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin),
+[gorilla/mux](https://github.com/gorilla/mux), and [Fiber](https://github.com/gofiber/fiber)
 have also been added by contributors as additional routers. We chose Echo because
 the `Context` object is a mockable interface, and it allows for some advanced
 testing.
@@ -34,7 +35,7 @@ We're going to use the OpenAPI example of the
 in the descriptions below, please have a look at it.
 
 In order to create a Go server to serve this exact schema, you would have to
-write a lot of boilerplate code to perform all the marshalling and unmarshalling
+write a lot of boilerplate code to perform all the marshaling and unmarshaling
 into objects which match the OpenAPI 3.0 definition. The code generator in this
 directory does a lot of that for you. You would run it like so:
 
@@ -111,7 +112,7 @@ type ServerInterface interface {
 These are the functions which you will implement yourself in order to create
 a server conforming to the API specification. Normally, all the arguments and
 parameters are stored on the `echo.Context` in handlers, so we do the tedious
-work of unmarshalling the JSON automatically, simply passing values into
+work of unmarshaling the JSON automatically, simply passing values into
 your handlers.
 
 Notice that `FindPetById` takes a parameter `id int64`. All path arguments
@@ -700,6 +701,8 @@ you can specify any combination of those.
   same package to compile.
 - `chi-server`: generate the Chi server boilerplate. This code is dependent on
   that produced by the `types` target.
+- `fiber`: generate the Fiber server boilerplate. This code is dependent
+  on that produced by the `types` target.
 - `client`: generate the client boilerplate. It, too, requires the types to be
   present in its package.
 - `spec`: embed the OpenAPI spec into the generated code as a gzipped blob.
diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go
index 09990d6..ae81acf 100644
--- a/cmd/oapi-codegen/oapi-codegen.go
+++ b/cmd/oapi-codegen/oapi-codegen.go
@@ -91,7 +91,7 @@ func main() {
 	// All flags below are deprecated, and will be removed in a future release. Please do not
 	// update their behavior.
 	flag.StringVar(&flagGenerate, "generate", "types,client,server,spec",
-		`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune".`)
+		`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune", "fiber".`)
 	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.")
@@ -293,7 +293,7 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
 	for _, f := range files {
 		// Recursively load subdirectory files, using the path relative to the templates
 		// directory as the key. This allows for overriding the files in the service-specific
-		// directories (e.g. echo, chi, etc.).
+		// directories (e.g. echo, chi, fiber, etc.).
 		if f.IsDir() {
 			subFiles, err := loadTemplateOverrides(path.Join(templatesDir, f.Name()))
 			if err != nil {
@@ -445,6 +445,8 @@ func generationTargets(cfg *codegen.Configuration, targets []string) error {
 		switch opt {
 		case "chi-server", "chi":
 			opts.ChiServer = true
+		case "fiber-server", "fiber":
+			opts.FiberServer = true
 		case "server", "echo-server", "echo":
 			opts.EchoServer = true
 		case "gin", "gin-server":
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 1d0fcb1..b9f7c13 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -427,7 +427,7 @@ func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error {
 
 	ctx.Set(BearerAuthScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.ListThings(ctx)
 	return err
 }
@@ -438,7 +438,7 @@ func (w *ServerInterfaceWrapper) AddThing(ctx echo.Context) error {
 
 	ctx.Set(BearerAuthScopes, []string{"things:w"})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.AddThing(ctx)
 	return err
 }
diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go
index 66505c5..59e517c 100644
--- a/examples/petstore-expanded/chi/api/petstore.gen.go
+++ b/examples/petstore-expanded/chi/api/petstore.gen.go
@@ -201,16 +201,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/examples/petstore-expanded/echo/api/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go
index a71407f..bb088e0 100644
--- a/examples/petstore-expanded/echo/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/echo/api/petstore-server.gen.go
@@ -60,7 +60,7 @@ func (w *ServerInterfaceWrapper) FindPets(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.FindPets(ctx, params)
 	return err
 }
@@ -69,7 +69,7 @@ func (w *ServerInterfaceWrapper) FindPets(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) AddPet(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.AddPet(ctx)
 	return err
 }
@@ -85,7 +85,7 @@ func (w *ServerInterfaceWrapper) DeletePet(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.DeletePet(ctx, id)
 	return err
 }
@@ -101,7 +101,7 @@ func (w *ServerInterfaceWrapper) FindPetByID(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.FindPetByID(ctx, id)
 	return err
 }
diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
new file mode 100644
index 0000000..a55486c
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
@@ -0,0 +1,246 @@
+// 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/url"
+	"path"
+	"strings"
+
+	"github.com/deepmap/oapi-codegen/pkg/runtime"
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gofiber/fiber/v2"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+	// Returns all pets
+	// (GET /pets)
+	FindPets(c *fiber.Ctx, params FindPetsParams) error
+	// Creates a new pet
+	// (POST /pets)
+	AddPet(c *fiber.Ctx) error
+	// Deletes a pet by ID
+	// (DELETE /pets/{id})
+	DeletePet(c *fiber.Ctx, id int64) error
+	// Returns a pet by ID
+	// (GET /pets/{id})
+	FindPetByID(c *fiber.Ctx, id int64) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+	Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+// FindPets operation middleware
+func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error {
+
+	var err error
+
+	// Parameter object where we will unmarshal all parameters from the context
+	var params FindPetsParams
+
+	var query url.Values
+	query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+	}
+
+	// ------------- Optional query parameter "tags" -------------
+
+	err = runtime.BindQueryParameter("form", true, false, "tags", query, &params.Tags)
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter tags: %w", err).Error())
+	}
+
+	// ------------- Optional query parameter "limit" -------------
+
+	err = runtime.BindQueryParameter("form", true, false, "limit", query, &params.Limit)
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter limit: %w", err).Error())
+	}
+
+	return siw.Handler.FindPets(c, params)
+}
+
+// AddPet operation middleware
+func (siw *ServerInterfaceWrapper) AddPet(c *fiber.Ctx) error {
+
+	return siw.Handler.AddPet(c)
+}
+
+// DeletePet operation middleware
+func (siw *ServerInterfaceWrapper) DeletePet(c *fiber.Ctx) error {
+
+	var err error
+
+	// ------------- Path parameter "id" -------------
+	var id int64
+
+	err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+	}
+
+	return siw.Handler.DeletePet(c, id)
+}
+
+// FindPetByID operation middleware
+func (siw *ServerInterfaceWrapper) FindPetByID(c *fiber.Ctx) error {
+
+	var err error
+
+	// ------------- Path parameter "id" -------------
+	var id int64
+
+	err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+	}
+
+	return siw.Handler.FindPetByID(c, id)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+	BaseURL     string
+	Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+	RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+	wrapper := ServerInterfaceWrapper{
+		Handler: si,
+	}
+
+	for _, m := range options.Middlewares {
+		router.Use(m)
+	}
+
+	router.Get(options.BaseURL+"/pets", wrapper.FindPets)
+
+	router.Post(options.BaseURL+"/pets", wrapper.AddPet)
+
+	router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet)
+
+	router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
+
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+	"H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
+	"I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
+	"od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
+	"9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
+	"MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
+	"czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
+	"Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
+	"/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
+	"m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
+	"2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
+	"MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
+	"L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
+	"HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
+	"S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
+	"5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
+	"w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
+	"3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
+	"MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
+	"mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
+	"4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
+	"DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
+	"1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
+	"Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
+	"zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
+	"ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
+	"zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
+	"FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
+	"97cAAAD//ykDnxlaEgAA",
+}
+
+// GetSwagger returns the content of the embedded swagger specification file
+// or error if failed to decode
+func decodeSpec() ([]byte, error) {
+	zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+	if err != nil {
+		return nil, fmt.Errorf("error base64 decoding spec: %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/fiber/api/petstore-types.gen.go b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
new file mode 100644
index 0000000..16bbe20
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
@@ -0,0 +1,46 @@
+// 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
+
+// Error defines model for Error.
+type Error struct {
+	// Code Error code
+	Code int32 `json:"code"`
+
+	// Message Error message
+	Message string `json:"message"`
+}
+
+// NewPet defines model for NewPet.
+type NewPet struct {
+	// Name Name of the pet
+	Name string `json:"name"`
+
+	// Tag Type of the pet
+	Tag *string `json:"tag,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+	// Id Unique id of the pet
+	Id int64 `json:"id"`
+
+	// Name Name of the pet
+	Name string `json:"name"`
+
+	// Tag Type of the pet
+	Tag *string `json:"tag,omitempty"`
+}
+
+// FindPetsParams defines parameters for FindPets.
+type FindPetsParams struct {
+	// Tags tags to filter by
+	Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+
+	// Limit maximum number of results to return
+	Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
+}
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = NewPet
diff --git a/examples/petstore-expanded/fiber/api/petstore.go b/examples/petstore-expanded/fiber/api/petstore.go
new file mode 100644
index 0000000..60ecd58
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/petstore.go
@@ -0,0 +1,132 @@
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+
+package api
+
+import (
+	"fmt"
+	"net/http"
+	"sync"
+
+	"github.com/gofiber/fiber/v2"
+)
+
+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(c *fiber.Ctx, code int, message string) error {
+
+	petErr := Error{
+		Code:    int32(code),
+		Message: message,
+	}
+
+	return c.Status(code).JSON(petErr)
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(c *fiber.Ctx, params FindPetsParams) error {
+
+	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
+			}
+		}
+	}
+
+	return c.Status(http.StatusOK).JSON(result)
+}
+
+func (p *PetStore) AddPet(c *fiber.Ctx) error {
+
+	// We expect a NewPet object in the request body.
+	var newPet NewPet
+
+	if err := c.BodyParser(&newPet); err != nil {
+		return sendPetStoreError(c, http.StatusBadRequest, "Invalid format for NewPet")
+	}
+
+	// We now have a pet, let's add it to our "database".
+
+	// We're always asynchronous, so lock unsafe operations below
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	// We handle pets, not NewPets, which have an additional ID field
+	var pet 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
+	return c.Status(http.StatusCreated).JSON(pet)
+}
+
+func (p *PetStore) FindPetByID(c *fiber.Ctx, id int64) error {
+
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	pet, found := p.Pets[id]
+	if !found {
+		return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+	}
+
+	return c.Status(http.StatusOK).JSON(pet)
+}
+
+func (p *PetStore) DeletePet(c *fiber.Ctx, id int64) error {
+
+	p.Lock.Lock()
+	defer p.Lock.Unlock()
+
+	_, found := p.Pets[id]
+	if !found {
+		return sendPetStoreError(c, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+	}
+	delete(p.Pets, id)
+
+	c.Status(http.StatusNoContent)
+	return nil
+}
diff --git a/examples/petstore-expanded/fiber/api/server.cfg.yaml b/examples/petstore-expanded/fiber/api/server.cfg.yaml
new file mode 100644
index 0000000..91ef133
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/server.cfg.yaml
@@ -0,0 +1,5 @@
+package: api
+generate:
+  fiber-server: true
+  embedded-spec: true
+output: petstore-server.gen.go
diff --git a/examples/petstore-expanded/fiber/api/types.cfg.yaml b/examples/petstore-expanded/fiber/api/types.cfg.yaml
new file mode 100644
index 0000000..9ac30e1
--- /dev/null
+++ b/examples/petstore-expanded/fiber/api/types.cfg.yaml
@@ -0,0 +1,4 @@
+package: api
+generate:
+  models: true
+output: petstore-types.gen.go
diff --git a/examples/petstore-expanded/fiber/petstore.go b/examples/petstore-expanded/fiber/petstore.go
new file mode 100644
index 0000000..344752b
--- /dev/null
+++ b/examples/petstore-expanded/fiber/petstore.go
@@ -0,0 +1,57 @@
+// 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"
+	"os"
+
+	"github.com/gofiber/fiber/v2"
+
+	"github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
+	middleware "github.com/deepmap/oapi-codegen/pkg/fiber-middleware"
+)
+
+func main() {
+
+	var port = flag.Int("port", 8080, "Port for test HTTP server")
+
+	flag.Parse()
+
+	// Create an instance of our handler which satisfies the generated interface
+	petStore := api.NewPetStore()
+
+	s := NewFiberPetServer(petStore)
+
+	// And we serve HTTP until the world ends.
+	log.Fatal(s.Listen(fmt.Sprintf("localhost:%d", *port)))
+}
+
+func NewFiberPetServer(petStore *api.PetStore) *fiber.App {
+
+	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
+
+	// This is how you set up a basic fiber router
+	app := fiber.New()
+
+	// Use our validation middleware to check all requests against the
+	// OpenAPI schema.
+	app.Use(middleware.OapiRequestValidator(swagger))
+
+	// We now register our petStore above as the handler for the interface
+	api.RegisterHandlers(app, petStore)
+
+	return app
+}
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index b55ecd0..654fdd4 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -201,16 +201,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/examples/petstore-expanded/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go
index 822dee7..3008bd8 100644
--- a/examples/petstore-expanded/strict/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go
@@ -161,16 +161,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/go.mod b/go.mod
index 705e680..f003ee7 100644
--- a/go.mod
+++ b/go.mod
@@ -5,19 +5,21 @@ require (
 	github.com/getkin/kin-openapi v0.117.0
 	github.com/gin-gonic/gin v1.9.1
 	github.com/go-chi/chi/v5 v5.0.8
+	github.com/gofiber/fiber/v2 v2.46.0
 	github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/mux v1.8.0
 	github.com/labstack/echo/v4 v4.10.2
 	github.com/lestrrat-go/jwx v1.2.25
 	github.com/matryer/moq v0.3.1
-	github.com/stretchr/testify v1.8.3
+	github.com/stretchr/testify v1.8.4
 	golang.org/x/text v0.9.0
-	golang.org/x/tools v0.9.2
+	golang.org/x/tools v0.9.3
 	gopkg.in/yaml.v2 v2.4.0
 )
 
 require (
+	github.com/andybalholm/brotli v1.0.5 // indirect
 	github.com/bytedance/sonic v1.9.1 // indirect
 	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
@@ -34,6 +36,7 @@ require (
 	github.com/invopop/yaml v0.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.16.3 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.4 // indirect
 	github.com/labstack/gommon v0.4.0 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
@@ -45,18 +48,26 @@ require (
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
 	github.com/perimeterx/marshmallow v1.1.4 // indirect
+	github.com/philhofer/fwd v1.1.2 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
+	github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
 	github.com/stretchr/objx v0.5.0 // indirect
+	github.com/tinylib/msgp v1.1.8 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.11 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
+	github.com/valyala/fasthttp v1.47.0 // indirect
 	github.com/valyala/fasttemplate v1.2.2 // indirect
+	github.com/valyala/tcplisten v1.0.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
 	golang.org/x/crypto v0.9.0 // indirect
 	golang.org/x/mod v0.10.0 // indirect
diff --git a/go.sum b/go.sum
index 080bf51..da0b9ce 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,6 @@
 github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
+github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
 github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
@@ -43,6 +45,8 @@ github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncV
 github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns=
+github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc=
 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
 github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -62,6 +66,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
+github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
+github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
 github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
@@ -102,6 +108,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -115,10 +123,20 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ
 github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
 github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
 github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
+github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
+github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
+github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
+github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
+github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -132,8 +150,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
 github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
+github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
+github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
@@ -142,42 +164,84 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
 github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
+github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
 github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
 golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
 golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
 golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
 golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.9.2 h1:UXbndbirwCAx6TULftIfie/ygDNCwxEie+IiNP1IcNc=
-golang.org/x/tools v0.9.2/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
+golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index 1cf431e..6cb5fec 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -189,6 +189,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 		}
 	}
 
+	var fiberServerOut string
+	if opts.Generate.FiberServer {
+		fiberServerOut, err = GenerateFiberServer(t, ops)
+		if err != nil {
+			return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
+		}
+	}
+
 	var ginServerOut string
 	if opts.Generate.GinServer {
 		ginServerOut, err = GenerateGinServer(t, ops)
@@ -298,6 +306,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 		}
 	}
 
+	if opts.Generate.FiberServer {
+		_, err = w.WriteString(fiberServerOut)
+		if err != nil {
+			return "", fmt.Errorf("error writing server path handlers: %w", err)
+		}
+	}
+
 	if opts.Generate.GinServer {
 		_, err = w.WriteString(ginServerOut)
 		if err != nil {
@@ -820,7 +835,7 @@ func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, type
 func SanitizeCode(goCode string) string {
 	// remove any byte-order-marks which break Go-Code
 	// See: https://groups.google.com/forum/#!topic/golang-nuts/OToNIPdfkks
-	return strings.Replace(goCode, "\uFEFF", "", -1)
+	return strings.ReplaceAll(goCode, "\uFEFF", "")
 }
 
 // GetUserTemplateText attempts to retrieve the template text from a passed in URL or file
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index 8d7f2e6..9b64bfe 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -23,6 +23,7 @@ type Configuration struct {
 // 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
+	FiberServer   bool `yaml:"fiber-server,omitempty"`   // FiberServer specifies whether to generate fiber server boilerplate
 	EchoServer    bool `yaml:"echo-server,omitempty"`    // EchoServer specifies whether to generate echo server boilerplate
 	GinServer     bool `yaml:"gin-server,omitempty"`     // GinServer specifies whether to generate gin server boilerplate
 	GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate
@@ -113,6 +114,9 @@ func (o Configuration) Validate() error {
 	if o.Generate.ChiServer {
 		nServers++
 	}
+	if o.Generate.FiberServer {
+		nServers++
+	}
 	if o.Generate.EchoServer {
 		nServers++
 	}
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index ab09547..c802b53 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -293,12 +293,18 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini
 
 					var typeName string
 					switch {
+
 					// HAL+JSON:
 					case StringInArray(contentTypeName, contentTypesHalJSON):
 						typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName))
-					// JSON:
-					case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
+					case "application/json" == contentTypeName:
+						// if it's the standard application/json
 						typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName))
+					// Vendored JSON
+					case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
+						baseTypeName := fmt.Sprintf("%s%s", ToCamelCase(contentTypeName), ToCamelCase(responseName))
+
+						typeName = strings.ReplaceAll(baseTypeName, "Json", "JSON")
 					// YAML:
 					case StringInArray(contentTypeName, contentTypesYAML):
 						typeName = fmt.Sprintf("YAML%s", ToCamelCase(responseName))
@@ -913,6 +919,12 @@ func GenerateChiServer(t *template.Template, operations []OperationDefinition) (
 	return GenerateTemplates([]string{"chi/chi-interface.tmpl", "chi/chi-middleware.tmpl", "chi/chi-handler.tmpl"}, t, operations)
 }
 
+// GenerateFiberServer This function generates all the go code for the ServerInterface as well as
+// all the wrapper functions around our handlers.
+func GenerateFiberServer(t *template.Template, operations []OperationDefinition) (string, error) {
+	return GenerateTemplates([]string{"fiber/fiber-interface.tmpl", "fiber/fiber-middleware.tmpl", "fiber/fiber-handler.tmpl"}, t, operations)
+}
+
 // GenerateEchoServer This function generates all the go code for the ServerInterface as well as
 // all the wrapper functions around our handlers.
 func GenerateEchoServer(t *template.Template, operations []OperationDefinition) (string, error) {
@@ -932,16 +944,22 @@ func GenerateGorillaServer(t *template.Template, operations []OperationDefinitio
 }
 
 func GenerateStrictServer(t *template.Template, operations []OperationDefinition, opts Configuration) (string, error) {
-	templates := []string{"strict/strict-interface.tmpl"}
+
+	var templates []string
+
 	if opts.Generate.ChiServer || opts.Generate.GorillaServer {
-		templates = append(templates, "strict/strict-http.tmpl")
+		templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-http.tmpl")
 	}
 	if opts.Generate.EchoServer {
-		templates = append(templates, "strict/strict-echo.tmpl")
+		templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-echo.tmpl")
 	}
 	if opts.Generate.GinServer {
-		templates = append(templates, "strict/strict-gin.tmpl")
+		templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-gin.tmpl")
 	}
+	if opts.Generate.FiberServer {
+		templates = append(templates, "strict/strict-fiber-interface.tmpl", "strict/strict-fiber.tmpl")
+	}
+
 	return GenerateTemplates(templates, t, operations)
 }
 
@@ -956,7 +974,7 @@ func GenerateClient(t *template.Template, ops []OperationDefinition) (string, er
 }
 
 // GenerateClientWithResponses generates a client which extends the basic client which does response
-// unmarshalling.
+// unmarshaling.
 func GenerateClientWithResponses(t *template.Template, ops []OperationDefinition) (string, error) {
 	return GenerateTemplates([]string{"client-with-responses.tmpl"}, t, ops)
 }
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index eec2ad9..b811e7d 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -167,7 +167,7 @@ type TypeDefinition struct {
 }
 
 // ResponseTypeDefinition is an extension of TypeDefinition, specifically for
-// response unmarshalling in ClientWithResponses.
+// response unmarshaling in ClientWithResponses.
 type ResponseTypeDefinition struct {
 	TypeDefinition
 	// The content type name where this is used, eg, application/json
@@ -241,6 +241,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
 			GoType:         refType,
 			Description:    schema.Description,
 			DefineViaAlias: true,
+			OAPISchema:     schema,
 		}, nil
 	}
 
@@ -720,6 +721,9 @@ func additionalPropertiesType(schema Schema) string {
 	if schema.AdditionalPropertiesType.RefType != "" {
 		addPropsType = schema.AdditionalPropertiesType.RefType
 	}
+	if schema.AdditionalPropertiesType.OAPISchema != nil && schema.AdditionalPropertiesType.OAPISchema.Nullable {
+		addPropsType = "*" + addPropsType
+	}
 	return addPropsType
 }
 
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index bae1e30..dfaca18 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -102,7 +102,7 @@ func genResponsePayload(operationID string) string {
 	return buffer.String()
 }
 
-// genResponseUnmarshal generates unmarshalling steps for structured response payloads
+// genResponseUnmarshal generates unmarshaling steps for structured response payloads
 func genResponseUnmarshal(op *OperationDefinition) string {
 	var handledCaseClauses = make(map[string]string)
 	var unhandledCaseClauses = make(map[string]string)
@@ -134,7 +134,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
 			continue
 		}
 
-		// If there is no content-type then we have no unmarshalling to do:
+		// If there is no content-type then we have no unmarshaling to do:
 		if len(responseRef.Value.Content) == 0 {
 			caseAction := "break // No content-type"
 			caseClauseKey := "case " + getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName) + ":"
@@ -142,7 +142,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
 			continue
 		}
 
-		// If we made it this far then we need to handle unmarshalling for each content-type:
+		// If we made it this far then we need to handle unmarshaling for each content-type:
 		sortedContentKeys := SortedContentKeys(responseRef.Value.Content)
 		for _, contentTypeName := range sortedContentKeys {
 
@@ -229,7 +229,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
 	return buffer.String()
 }
 
-// buildUnmarshalCase builds an unmarshalling case clause for different content-types:
+// buildUnmarshalCase builds an unmarshaling case clause for different content-types:
 func buildUnmarshalCase(typeDefinition ResponseTypeDefinition, caseAction string, contentType string) (caseKey string, caseClause string) {
 	caseKey = fmt.Sprintf("%s.%s.%s", prefixLeastSpecific, contentType, typeDefinition.ResponseName)
 	caseClauseKey := getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName)
@@ -284,6 +284,7 @@ var TemplateFunctions = template.FuncMap{
 	"genParamNames":              genParamNames,
 	"genParamFmtString":          ReplacePathParamsWithStr,
 	"swaggerUriToEchoUri":        SwaggerUriToEchoUri,
+	"swaggerUriToFiberUri":       SwaggerUriToFiberUri,
 	"swaggerUriToChiUri":         SwaggerUriToChiUri,
 	"swaggerUriToGinUri":         SwaggerUriToGinUri,
 	"swaggerUriToGorillaUri":     SwaggerUriToGorillaUri,
diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl
index c83cc10..7b7c0ac 100644
--- a/pkg/codegen/templates/additional-properties.tmpl
+++ b/pkg/codegen/templates/additional-properties.tmpl
@@ -40,7 +40,7 @@ func (a *{{.TypeName}}) UnmarshalJSON(b []byte) error {
             var fieldVal {{$addType}}
             err := json.Unmarshal(fieldBuf, &fieldVal)
             if err != nil {
-                return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+                return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
             }
             a.AdditionalProperties[fieldName] = fieldVal
         }
diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl
index e99bbeb..33b89c8 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -25,7 +25,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
   {{if .IsJson}}
   err = json.Unmarshal([]byte(chi.URLParam(r, "{{.ParamName}}")), &{{$varName}})
   if err != nil {
-    siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+    siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
     return
   }
   {{end}}
@@ -62,7 +62,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
           var value {{.TypeDef}}
           err = json.Unmarshal([]byte(paramValue), &value)
           if err != nil {
-            siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
             return
           }
 
@@ -101,7 +101,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
         {{if .IsJson}}
           err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
           if err != nil {
-            siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
             return
           }
         {{end}}
@@ -146,7 +146,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
 
         err = json.Unmarshal([]byte(decoded), &value)
         if err != nil {
-          siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
           return
         }
 
@@ -204,16 +204,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
     return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
     ParamName string
     Err error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-    return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+    return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
     return e.Err
 }
 
diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl
index f2e4dbc..21ba626 100644
--- a/pkg/codegen/templates/echo/echo-wrappers.tmpl
+++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl
@@ -14,7 +14,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
 {{if .IsJson}}
     err = json.Unmarshal([]byte(ctx.Param("{{.ParamName}}")), &{{$varName}})
     if err != nil {
-        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter '{{.ParamName}}' as JSON")
+        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
     }
 {{end}}
 {{if .IsStyled}}
@@ -50,7 +50,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
     var value {{.TypeDef}}
     err = json.Unmarshal([]byte(paramValue), &value)
     if err != nil {
-        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter '{{.ParamName}}' as JSON")
+        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
     }
     params.{{.GoName}} = {{if not .Required}}&{{end}}value
     {{end}}
@@ -75,7 +75,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
 {{if .IsJson}}
         err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
         if err != nil {
-            return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter '{{.ParamName}}' as JSON")
+            return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
         }
 {{end}}
 {{if .IsStyled}}
@@ -105,7 +105,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
     }
     err = json.Unmarshal([]byte(decoded), &value)
     if err != nil {
-        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter '{{.ParamName}}' as JSON")
+        return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
     }
     params.{{.GoName}} = {{if not .Required}}&{{end}}value
     {{end}}
@@ -124,7 +124,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
 {{end}}{{/* .CookieParams */}}
 
 {{end}}{{/* .RequiresParamObject */}}
-    // Invoke the callback with all the unmarshalled arguments
+    // Invoke the callback with all the unmarshaled arguments
     err = w.Handler.{{.OperationId}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
     return err
 }
diff --git a/pkg/codegen/templates/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl
new file mode 100644
index 0000000..4a55b3c
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-handler.tmpl
@@ -0,0 +1,25 @@
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+    BaseURL string
+    Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+  RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+{{if .}}wrapper := ServerInterfaceWrapper{
+Handler: si,
+}
+
+for _, m := range options.Middlewares {
+    router.Use(m)
+}
+{{end}}
+{{range .}}
+router.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToFiberUri}}", wrapper.{{.OperationId}})
+{{end}}
+}
diff --git a/pkg/codegen/templates/fiber/fiber-interface.tmpl b/pkg/codegen/templates/fiber/fiber-interface.tmpl
new file mode 100644
index 0000000..8ef90a8
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-interface.tmpl
@@ -0,0 +1,7 @@
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+{{range .}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{.OperationId}}(c *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error
+{{end}}
+}
diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
new file mode 100644
index 0000000..fd8d00d
--- /dev/null
+++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
@@ -0,0 +1,169 @@
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+    Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+{{range .}}{{$opid := .OperationId}}
+
+// {{$opid}} operation middleware
+func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
+
+  {{if or .RequiresParamObject (gt (len .PathParams) 0) }}
+  var err error
+  {{end}}
+
+  {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
+  var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
+
+  {{if .IsPassThrough}}
+  {{$varName}} = c.Query("{{.ParamName}}")
+  {{end}}
+  {{if .IsJson}}
+  err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
+  if err != nil {
+    return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+  }
+  {{end}}
+  {{if .IsStyled}}
+  err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}})
+  if err != nil {
+    return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+  }
+  {{end}}
+
+  {{end}}
+
+{{range .SecurityDefinitions}}
+  c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+{{end}}
+
+  {{if .RequiresParamObject}}
+    // Parameter object where we will unmarshal all parameters from the context
+    var params {{.OperationId}}Params
+
+    {{if .QueryParams}}
+    var query url.Values
+    query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+    if err != nil {
+      return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+    }
+    {{end}}
+
+    {{range $paramIdx, $param := .QueryParams}}
+      {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+        // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+      {{ end }}
+      {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+        if paramValue := c.Query("{{.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 {
+            return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+          }
+
+          params.{{.GoName}} = {{if not .Required}}&{{end}}value
+        {{end}}
+        }{{if .Required}} else {
+            err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found")
+            c.Status(fiber.StatusBadRequest).JSON(err)
+            return err
+        }{{end}}
+      {{end}}
+      {{if .IsStyled}}
+      err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", query, &params.{{.GoName}})
+      if err != nil {
+        return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+      }
+      {{end}}
+  {{end}}
+
+    {{if .HeaderParams}}
+      headers := c.GetReqHeaders()
+
+      {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
+        if value, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+          var {{.GoName}} {{.TypeDef}}
+
+        {{if .IsPassThrough}}
+          params.{{.GoName}} = {{if not .Required}}&{{end}}value
+        {{end}}
+
+        {{if .IsJson}}
+          err = json.Unmarshal([]byte(value), &{{.GoName}})
+          if err != nil {
+            return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+          }
+        {{end}}
+
+        {{if .IsStyled}}
+          err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, value, &{{.GoName}})
+          if err != nil {
+            return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+          }
+        {{end}}
+
+          params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+
+        } {{if .Required}}else {
+            err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err)
+            return fiber.NewError(fiber.StatusBadRequest, err.Error())
+        }{{end}}
+
+      {{end}}
+    {{end}}
+
+    {{range .CookieParams}}
+      var cookie string
+
+      if cookie = c.Cookies("{{.ParamName}}"); cookie == "" {
+
+      {{- if .IsPassThrough}}
+        params.{{.GoName}} = {{if not .Required}}&{{end}}cookie
+      {{end}}
+
+      {{- if .IsJson}}
+        var value {{.TypeDef}}
+        var decoded string
+        decoded, err := url.QueryUnescape(cookie)
+        if err != nil {
+          return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}': %w", err).Error())
+        }
+
+        err = json.Unmarshal([]byte(decoded), &value)
+        if err != nil {
+          return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+        }
+
+        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+      {{end}}
+
+      {{- if .IsStyled}}
+        var value {{.TypeDef}}
+        err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
+        if err != nil {
+          return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
+        }
+        params.{{.GoName}} = {{if not .Required}}&{{end}}value
+      {{end}}
+
+      }
+
+      {{- if .Required}} else {
+        err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found")
+        return fiber.NewError(fiber.StatusBadRequest, err.Error())
+      }
+      {{- end}}
+    {{end}}
+  {{end}}
+
+  return siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+}
+{{end}}
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index e30e839..d1ac194 100644
--- a/pkg/codegen/templates/gin/gin-wrappers.tmpl
+++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl
@@ -25,7 +25,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
   {{if .IsJson}}
   err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
   if err != nil {
-    siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
+    siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
     return
   }
   {{end}}
@@ -62,7 +62,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
           var value {{.TypeDef}}
           err = json.Unmarshal([]byte(paramValue), &value)
           if err != nil {
-            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON: %s", err), http.StatusBadRequest)
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %s", err), http.StatusBadRequest)
             return
           }
 
@@ -102,7 +102,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
         {{if .IsJson}}
           err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
           if err != nil {
-            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
             return
           }
         {{end}}
@@ -146,7 +146,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
 
         err = json.Unmarshal([]byte(decoded), &value)
         if err != nil {
-            siw.ErrorHandler(c, fmt.Errorf("Error unmarshalling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
+            siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
             return
         }
 
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
index 1360891..b208fa2 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -25,7 +25,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
   {{if .IsJson}}
   err = json.Unmarshal([]byte(mux.Vars(r)["{{.ParamName}}"]), &{{$varName}})
   if err != nil {
-    siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+    siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
     return
   }
   {{end}}
@@ -62,7 +62,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
           var value {{.TypeDef}}
           err = json.Unmarshal([]byte(paramValue), &value)
           if err != nil {
-            siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
             return
           }
 
@@ -101,7 +101,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
         {{if .IsJson}}
           err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
           if err != nil {
-            siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+            siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
             return
           }
         {{end}}
@@ -146,7 +146,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
 
         err = json.Unmarshal([]byte(decoded), &value)
         if err != nil {
-          siw.ErrorHandlerFunc(w, r, &UnmarshallingParamError{ParamName: "{{.ParamName}}", Err: err})
+          siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
           return
         }
 
@@ -204,16 +204,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
     return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
     ParamName string
     Err error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-    return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+    return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
     return e.Err
 }
 
diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl
index ef43ef3..f69a492 100644
--- a/pkg/codegen/templates/imports.tmpl
+++ b/pkg/codegen/templates/imports.tmpl
@@ -27,6 +27,7 @@ import (
 	"github.com/go-chi/chi/v5"
 	"github.com/labstack/echo/v4"
 	"github.com/gin-gonic/gin"
+	"github.com/gofiber/fiber/v2"
 	"github.com/gorilla/mux"
 	{{- range .ExternalImports}}
 	{{ . }}
diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
new file mode 100644
index 0000000..6fdef09
--- /dev/null
+++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
@@ -0,0 +1,137 @@
+{{range .}}
+    {{$opid := .OperationId -}}
+    type {{$opid | ucFirst}}RequestObject struct {
+        {{range .PathParams -}}
+            {{.GoName | ucFirst}} {{.TypeDef}} {{.JsonTag}}
+        {{end -}}
+        {{if .RequiresParamObject -}}
+            Params {{$opid}}Params
+        {{end -}}
+        {{if .HasMaskedRequestContentTypes -}}
+            ContentType string
+        {{end -}}
+        {{$multipleBodies := gt (len .Bodies) 1 -}}
+        {{range .Bodies -}}
+            {{if $multipleBodies}}{{.NameTag}}{{end}}Body {{if eq .NameTag "Multipart"}}*multipart.Reader{{else if ne .NameTag ""}}*{{$opid}}{{.NameTag}}RequestBody{{else}}io.Reader{{end}}
+        {{end -}}
+    }
+
+    type {{$opid | ucFirst}}ResponseObject interface {
+        Visit{{$opid}}Response(ctx *fiber.Ctx) error
+    }
+
+    {{range .Responses}}
+        {{$statusCode := .StatusCode -}}
+        {{$hasHeaders := ne 0 (len .Headers) -}}
+        {{$fixedStatusCode := .HasFixedStatusCode -}}
+        {{$isRef := .IsRef -}}
+        {{$ref := .Ref  | ucFirst -}}
+        {{$headers := .Headers -}}
+
+        {{if (and $hasHeaders (not $isRef)) -}}
+            type {{$opid}}{{$statusCode}}ResponseHeaders struct {
+                {{range .Headers -}}
+                    {{.GoName}} {{.Schema.TypeDecl}}
+                {{end -}}
+            }
+        {{end}}
+
+        {{range .Contents}}
+            {{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
+            {{if and $fixedStatusCode $isRef -}}
+                type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
+            {{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
+                type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+            {{else -}}
+                type {{$receiverTypeName}} struct {
+                    Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+                    {{if $hasHeaders -}}
+                        Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
+                    {{end -}}
+
+                    {{if not $fixedStatusCode -}}
+                        StatusCode int
+                    {{end -}}
+
+                    {{if not .HasFixedContentType -}}
+                        ContentType string
+                    {{end -}}
+
+                    {{if not .IsSupported -}}
+                        ContentLength int64
+                    {{end -}}
+                }
+            {{end}}
+
+            func (response {{$receiverTypeName}}) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
+                {{range $headers -}}
+                    ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+                {{end -}}
+                {{if eq .NameTag "Multipart" -}}
+                    writer := multipart.NewWriter(ctx.Response().BodyWriter())
+                {{end -}}
+                ctx.Response().Header.Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
+                {{if not .IsSupported -}}
+                    if response.ContentLength != 0 {
+                        ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+                    }
+                {{end -}}
+                ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+                {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
+                {{if eq .NameTag "JSON" -}}
+                    return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}})
+                {{else if eq .NameTag "Text" -}}
+                    _, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
+                    return err
+                {{else if eq .NameTag "Formdata" -}}
+                    if form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil); err != nil {
+                        return err
+                    } else {
+                        _, err := ctx.WriteString(form.Encode())
+                        return err
+                    }
+                {{else if eq .NameTag "Multipart" -}}
+                    defer writer.Close()
+                    return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
+                {{else -}}
+                    if closer, ok := response.Body.(io.ReadCloser); ok {
+                        defer closer.Close()
+                    }
+                    _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+                    return err
+                {{end}}{{/* if eq .NameTag "JSON" */ -}}
+            }
+        {{end}}
+
+        {{if eq 0 (len .Contents) -}}
+            {{if and $fixedStatusCode $isRef -}}
+                type {{$opid}}{{$statusCode}}Response = {{$ref}}Response
+            {{else -}}
+                type {{$opid}}{{$statusCode}}Response struct {
+                    {{if $hasHeaders -}}
+                        Headers {{if $isRef}}{{$ref}}{{else}}{{$opid}}{{$statusCode}}{{end}}ResponseHeaders
+                    {{end}}
+                    {{if not $fixedStatusCode -}}
+                        StatusCode int
+                    {{end -}}
+                }
+            {{end -}}
+            func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
+                {{range $headers -}}
+                    ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+                {{end -}}
+                ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+                return nil
+            }
+        {{end}}
+    {{end}}
+{{end}}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+{{range .}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{$opid := .OperationId -}}
+{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
+{{end}}{{/* range . */ -}}
+}
diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl
new file mode 100644
index 0000000..38a819f
--- /dev/null
+++ b/pkg/codegen/templates/strict/strict-fiber.tmpl
@@ -0,0 +1,80 @@
+type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
+
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+    return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+    ssi StrictServerInterface
+    middlewares []StrictMiddlewareFunc
+}
+
+{{range .}}
+    {{$opid := .OperationId}}
+    // {{$opid}} operation middleware
+    func (sh *strictHandler) {{.OperationId}}(ctx *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error {
+        var request {{$opid | ucFirst}}RequestObject
+
+        {{range .PathParams -}}
+            {{$varName := .GoVariableName -}}
+            request.{{.GoName}} = {{.GoVariableName}}
+        {{end -}}
+
+        {{if .RequiresParamObject -}}
+            request.Params = params
+        {{end -}}
+
+        {{ if .HasMaskedRequestContentTypes -}}
+            request.ContentType = string(ctx.Request().Header.ContentType())
+        {{end -}}
+
+        {{$multipleBodies := gt (len .Bodies) 1 -}}
+        {{range .Bodies -}}
+            {{if $multipleBodies}}if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "{{.ContentType}}") { {{end}}
+                {{if eq .NameTag "JSON" -}}
+                    var body {{$opid}}{{.NameTag}}RequestBody
+                    if err := ctx.BodyParser(&body); err != nil {
+                        return fiber.NewError(fiber.StatusBadRequest, err.Error())
+                    }
+                    request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+                {{else if eq .NameTag "Formdata" -}}
+                    var body {{$opid}}{{.NameTag}}RequestBody
+                    if err := ctx.BodyParser(&body); err != nil {
+                        return fiber.NewError(fiber.StatusBadRequest, err.Error())
+                    }
+                    request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+                {{else if eq .NameTag "Multipart" -}}
+                    request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+                {{else if eq .NameTag "Text" -}}
+                    data := ctx.Request().Body()
+                    body := {{$opid}}{{.NameTag}}RequestBody(data)
+                    request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+                {{else -}}
+                    request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = bytes.NewReader(ctx.Request().Body())
+                {{end}}{{/* if eq .NameTag "JSON" */ -}}
+            {{if $multipleBodies}}}{{end}}
+        {{end}}{{/* range .Bodies */}}
+
+        handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+            return sh.ssi.{{.OperationId}}(ctx.UserContext(), request.({{$opid | ucFirst}}RequestObject))
+        }
+        for _, middleware := range sh.middlewares {
+            handler = middleware(handler, "{{.OperationId}}")
+        }
+
+        response, err := handler(ctx, request)
+
+        if err != nil {
+            return fiber.NewError(fiber.StatusBadRequest, err.Error())
+        } else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok {
+            if err := validResponse.Visit{{$opid}}Response(ctx); err != nil {
+                return fiber.NewError(fiber.StatusBadRequest, err.Error())
+            }
+        } else if response != nil {
+            return fmt.Errorf("Unexpected response type: %T", response)
+        }
+        return nil
+    }
+{{end}}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 6fb031e..cf8826e 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -728,8 +728,8 @@ func stringToGoCommentWithPrefix(in, prefix string) string {
 	}
 
 	// Normalize newlines from Windows/Mac to Linux
-	in = strings.Replace(in, "\r\n", "\n", -1)
-	in = strings.Replace(in, "\r", "\n", -1)
+	in = strings.ReplaceAll(in, "\r\n", "\n")
+	in = strings.ReplaceAll(in, "\r", "\n")
 
 	// Add comment to each line
 	var lines []string
diff --git a/pkg/fiber-middleware/oapi_validate.go b/pkg/fiber-middleware/oapi_validate.go
new file mode 100644
index 0000000..ef30dd8
--- /dev/null
+++ b/pkg/fiber-middleware/oapi_validate.go
@@ -0,0 +1,196 @@
+// Package middleware implements middleware function for server implementations,
+// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification.
+// When OAPI validation fails on the request, we return an HTTP/400.
+package middleware
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"strings"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/getkin/kin-openapi/openapi3filter"
+	"github.com/getkin/kin-openapi/routers"
+	"github.com/getkin/kin-openapi/routers/gorillamux"
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/fiber/v2/middleware/adaptor"
+)
+
+type ctxKeyFiberContext struct{}
+type ctxKeyUserData struct{}
+
+// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path
+func OapiValidatorFromYamlFile(path string) (fiber.Handler, error) {
+
+	data, err := os.ReadFile(path)
+	if err != nil {
+		return nil, fmt.Errorf("error reading %s: %s", path, err)
+	}
+
+	swagger, err := openapi3.NewLoader().LoadFromData(data)
+	if err != nil {
+		return nil, fmt.Errorf("error parsing %s as Swagger YAML: %s",
+			path, err)
+	}
+
+	return OapiRequestValidator(swagger), nil
+}
+
+// OapiRequestValidator is a fiber middleware function which validates incoming HTTP requests
+// to make sure that they conform to the given OAPI 3.0 specification. When
+// OAPI validation fails on the request, we return an HTTP/400 with error message
+func OapiRequestValidator(swagger *openapi3.T) fiber.Handler {
+	return OapiRequestValidatorWithOptions(swagger, nil)
+}
+
+// ErrorHandler is called when there is an error in validation
+type ErrorHandler func(c *fiber.Ctx, message string, statusCode int)
+
+// MultiErrorHandler is called when oapi returns a MultiError type
+type MultiErrorHandler func(openapi3.MultiError) error
+
+// Options to customize request validation. These are passed through to
+// openapi3filter.
+type Options struct {
+	Options           openapi3filter.Options
+	ErrorHandler      ErrorHandler
+	ParamDecoder      openapi3filter.ContentParameterDecoder
+	UserData          interface{}
+	MultiErrorHandler MultiErrorHandler
+}
+
+// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
+func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) fiber.Handler {
+
+	router, err := gorillamux.NewRouter(swagger)
+	if err != nil {
+		panic(err)
+	}
+
+	return func(c *fiber.Ctx) error {
+
+		err := ValidateRequestFromContext(c, router, options)
+		if err != nil {
+			if options != nil && options.ErrorHandler != nil {
+				options.ErrorHandler(c, err.Error(), http.StatusBadRequest)
+				// in case the handler didn't internally call Abort, stop the chain
+				return nil
+			} else {
+				// note: I am not sure if this is the best way to handle this
+				return fiber.NewError(http.StatusBadRequest, err.Error())
+			}
+		}
+		return c.Next()
+	}
+}
+
+// ValidateRequestFromContext is called from the middleware above and actually does the work
+// of validating a request.
+func ValidateRequestFromContext(c *fiber.Ctx, router routers.Router, options *Options) error {
+
+	r, err := adaptor.ConvertRequest(c, false)
+	if err != nil {
+		return err
+	}
+
+	route, pathParams, err := router.FindRoute(r)
+
+	// We failed to find a matching route for the request.
+	if err != nil {
+		switch e := err.(type) {
+		case *routers.RouteError:
+			// We've got a bad request, the path requested doesn't match
+			// either server, or path, or something.
+			return errors.New(e.Reason)
+		default:
+			// This should never happen today, but if our upstream code changes,
+			// we don't want to crash the server, so handle the unexpected error.
+			return fmt.Errorf("error validating route: %s", err.Error())
+		}
+	}
+
+	// Validate request
+	requestValidationInput := &openapi3filter.RequestValidationInput{
+		Request:    r,
+		PathParams: pathParams,
+		Route:      route,
+	}
+
+	// Pass the fiber context into the request validator, so that any callbacks
+	// which it invokes make it available.
+	requestContext := context.WithValue(context.Background(), ctxKeyFiberContext{}, c) //nolint:staticcheck
+
+	if options != nil {
+		requestValidationInput.Options = &options.Options
+		requestValidationInput.ParamDecoder = options.ParamDecoder
+		requestContext = context.WithValue(requestContext, ctxKeyUserData{}, options.UserData) //nolint:staticcheck
+	}
+
+	err = openapi3filter.ValidateRequest(requestContext, requestValidationInput)
+	if err != nil {
+		me := openapi3.MultiError{}
+		if errors.As(err, &me) {
+			errFunc := getMultiErrorHandlerFromOptions(options)
+			return errFunc(me)
+		}
+
+		switch e := err.(type) {
+		case *openapi3filter.RequestError:
+			// We've got a bad request
+			// Split up the verbose error by lines and return the first one
+			// openapi errors seem to be multi-line with a decent message on the first
+			errorLines := strings.Split(e.Error(), "\n")
+			return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
+		case *openapi3filter.SecurityRequirementsError:
+			return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error())
+		default:
+			// This should never happen today, but if our upstream code changes,
+			// we don't want to crash the server, so handle the unexpected error.
+			return fmt.Errorf("error validating request: %s", err)
+		}
+	}
+	return nil
+}
+
+// GetFiberContext gets the fiber context from within requests. It returns
+// nil if not found or wrong type.
+func GetFiberContext(c context.Context) *fiber.Ctx {
+	iface := c.Value(ctxKeyFiberContext{})
+	if iface == nil {
+		return nil
+	}
+
+	fiberCtx, ok := iface.(*fiber.Ctx)
+	if ok {
+		return fiberCtx
+	}
+	return nil
+}
+
+func GetUserData(c context.Context) interface{} {
+	return c.Value(ctxKeyUserData{})
+}
+
+// getMultiErrorHandlerFromOptions attempts to get the MultiErrorHandler from the options. If it is not set,
+// return a default handler
+func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
+	if options == nil {
+		return defaultMultiErrorHandler
+	}
+
+	if options.MultiErrorHandler == nil {
+		return defaultMultiErrorHandler
+	}
+
+	return options.MultiErrorHandler
+}
+
+// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
+// of all the errors. This method is called if there are no other
+// methods defined on the options.
+func defaultMultiErrorHandler(me openapi3.MultiError) error {
+	return fmt.Errorf("multiple errors encountered: %s", me)
+}
diff --git a/pkg/runtime/bindparam.go b/pkg/runtime/bindparam.go
index 4fc1b30..13d8706 100644
--- a/pkg/runtime/bindparam.go
+++ b/pkg/runtime/bindparam.go
@@ -68,7 +68,7 @@ func BindStyledParameterWithLocation(style string, explode bool, paramName strin
 	// If the destination implements encoding.TextUnmarshaler we use it for binding
 	if tu, ok := dest.(encoding.TextUnmarshaler); ok {
 		if err := tu.UnmarshalText([]byte(value)); err != nil {
-			return fmt.Errorf("error unmarshalling '%s' text as %T: %s", value, dest, err)
+			return fmt.Errorf("error unmarshaling '%s' text as %T: %s", value, dest, err)
 		}
 
 		return nil
@@ -82,7 +82,7 @@ func BindStyledParameterWithLocation(style string, explode bool, paramName strin
 
 	if t.Kind() == reflect.Struct {
 		// We've got a destination object, we'll create a JSON representation
-		// of the input value, and let the json library deal with the unmarshalling
+		// of the input value, and let the json library deal with the unmarshaling
 		parts, err := splitStyledParameter(style, explode, true, paramName, value)
 		if err != nil {
 			return err
@@ -233,7 +233,7 @@ func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error {
 // into the struct.
 func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error {
 	// We've got a destination object, we'll create a JSON representation
-	// of the input value, and let the json library deal with the unmarshalling
+	// of the input value, and let the json library deal with the unmarshaling
 	var fields []string
 	if explode {
 		fields = make([]string, len(parts))
@@ -462,7 +462,7 @@ func bindParamsToExplodedObject(paramName string, values url.Values, dest interf
 		return true, BindStringToObject(values.Get(paramName), dest)
 	}
 	if t.Kind() != reflect.Struct {
-		return false, fmt.Errorf("unmarshalling query arg '%s' into wrong type", paramName)
+		return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName)
 	}
 
 	fieldsPresent := false
diff --git a/pkg/runtime/bindstring.go b/pkg/runtime/bindstring.go
index efc9867..e256395 100644
--- a/pkg/runtime/bindstring.go
+++ b/pkg/runtime/bindstring.go
@@ -100,7 +100,7 @@ func BindStringToObject(src string, dst interface{}) error {
 	case reflect.Array:
 		if tu, ok := dst.(encoding.TextUnmarshaler); ok {
 			if err := tu.UnmarshalText([]byte(src)); err != nil {
-				return fmt.Errorf("error unmarshalling '%s' text as %T: %s", src, dst, err)
+				return fmt.Errorf("error unmarshaling '%s' text as %T: %s", src, dst, err)
 			}
 
 			return nil


Test patch:
diff --git a/examples/petstore-expanded/chi/petstore_test.go b/examples/petstore-expanded/chi/petstore_test.go
index e0e9a88..5e36439 100644
--- a/examples/petstore-expanded/chi/petstore_test.go
+++ b/examples/petstore-expanded/chi/petstore_test.go
@@ -53,7 +53,7 @@ func TestPetStore(t *testing.T) {
 
 		var resultPet api.Pet
 		err = json.NewDecoder(rr.Body).Decode(&resultPet)
-		assert.NoError(t, err, "error unmarshalling response")
+		assert.NoError(t, err, "error unmarshaling response")
 		assert.Equal(t, newPet.Name, resultPet.Name)
 		assert.Equal(t, *newPet.Tag, *resultPet.Tag)
 	})
@@ -146,7 +146,7 @@ func TestPetStore(t *testing.T) {
 
 		var petError api.Error
 		err = json.NewDecoder(rr.Body).Decode(&petError)
-		assert.NoError(t, err, "error unmarshalling PetError")
+		assert.NoError(t, err, "error unmarshaling PetError")
 		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
 
 		// Now, delete both real pets
diff --git a/examples/petstore-expanded/echo/petstore_test.go b/examples/petstore-expanded/echo/petstore_test.go
index b79d39d..36f5f42 100644
--- a/examples/petstore-expanded/echo/petstore_test.go
+++ b/examples/petstore-expanded/echo/petstore_test.go
@@ -72,7 +72,7 @@ func TestPetStore(t *testing.T) {
 	// sure that its fields match.
 	var resultPet models.Pet
 	err = result.UnmarshalBodyToObject(&resultPet)
-	assert.NoError(t, err, "error unmarshalling response")
+	assert.NoError(t, err, "error unmarshaling response")
 	assert.Equal(t, newPet.Name, resultPet.Name)
 	assert.Equal(t, *newPet.Tag, *resultPet.Tag)
 
@@ -106,7 +106,7 @@ func TestPetStore(t *testing.T) {
 	// We should have gotten a response from the server with the new pet. Make
 	// sure that its fields match.
 	err = result.UnmarshalBodyToObject(&resultPet)
-	assert.NoError(t, err, "error unmarshalling response")
+	assert.NoError(t, err, "error unmarshaling response")
 	petId2 := resultPet.Id
 
 	// Now, list all pets, we should have two
@@ -137,7 +137,7 @@ func TestPetStore(t *testing.T) {
 	result = testutil.NewRequest().Delete("/pets/7").Go(t, e)
 	assert.Equal(t, http.StatusNotFound, result.Code())
 	err = result.UnmarshalBodyToObject(&petError)
-	assert.NoError(t, err, "error unmarshalling PetError")
+	assert.NoError(t, err, "error unmarshaling PetError")
 	assert.Equal(t, int32(http.StatusNotFound), petError.Code)
 
 	// Now, delete both real pets
diff --git a/examples/petstore-expanded/fiber/petstore_test.go b/examples/petstore-expanded/fiber/petstore_test.go
new file mode 100644
index 0000000..e6a103a
--- /dev/null
+++ b/examples/petstore-expanded/fiber/petstore_test.go
@@ -0,0 +1,181 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"testing"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
+)
+
+func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) {
+
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	req := httptest.NewRequest("GET", u.RequestURI(), nil)
+	req.Header.Add("Accept", "application/json")
+	req.Host = u.Host
+
+	return app.Test(req)
+}
+
+func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (*http.Response, error) {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	buf, err := json.Marshal(jsonBody)
+	if err != nil {
+		return nil, err
+	}
+	req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
+	req.Header.Add("Accept", "application/json")
+	req.Header.Add("Content-Type", "application/json")
+	req.Host = u.Host
+	return app.Test(req)
+}
+
+func doDelete(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	req := httptest.NewRequest("DELETE", u.RequestURI(), nil)
+	req.Header.Add("Accept", "application/json")
+	req.Host = u.Host
+	return app.Test(req)
+}
+
+func TestPetStore(t *testing.T) {
+	var err error
+	store := api.NewPetStore()
+	fiberPetServer := NewFiberPetServer(store)
+
+	t.Run("Add pet", func(t *testing.T) {
+		tag := "TagOfSpot"
+		newPet := api.NewPet{
+			Name: "Spot",
+			Tag:  &tag,
+		}
+
+		rr, _ := doPost(t, fiberPetServer, "/pets", newPet)
+		assert.Equal(t, http.StatusCreated, rr.StatusCode)
+
+		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, fiberPetServer, fmt.Sprintf("/pets/%d", pet.Id))
+		assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+		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, fiberPetServer, "/pets/27179095781")
+		assert.Equal(t, http.StatusNotFound, rr.StatusCode)
+
+		var petError api.Error
+		err = json.NewDecoder(rr.Body).Decode(&petError)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+	})
+
+	t.Run("List all pets", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+		// Now, list all pets, we should have two
+		rr, _ := doGet(t, fiberPetServer, "/pets")
+		assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+		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, fiberPetServer, "/pets?tags=TagOfFido")
+		assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+		var petList []api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 1, len(petList))
+	})
+
+	t.Run("Filter pets by tag", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+		// Filter pets by non existent tag, we should have 0
+		rr, _ := doGet(t, fiberPetServer, "/pets?tags=NotExists")
+		assert.Equal(t, http.StatusOK, rr.StatusCode)
+
+		var petList []api.Pet
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 0, len(petList))
+	})
+
+	t.Run("Delete pets", func(t *testing.T) {
+		store.Pets = map[int64]api.Pet{1: {}, 2: {}}
+
+		// Let's delete non-existent pet
+		rr, _ := doDelete(t, fiberPetServer, "/pets/7")
+		assert.Equal(t, http.StatusNotFound, rr.StatusCode)
+
+		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, _ = doDelete(t, fiberPetServer, "/pets/1")
+		assert.Equal(t, http.StatusNoContent, rr.StatusCode)
+
+		rr, _ = doDelete(t, fiberPetServer, "/pets/2")
+		assert.Equal(t, http.StatusNoContent, rr.StatusCode)
+
+		// Should have no pets left.
+		var petList []api.Pet
+		rr, _ = doGet(t, fiberPetServer, "/pets")
+		assert.Equal(t, http.StatusOK, rr.StatusCode)
+		err = json.NewDecoder(rr.Body).Decode(&petList)
+		assert.NoError(t, err, "error getting response", err)
+		assert.Equal(t, 0, len(petList))
+	})
+}
diff --git a/examples/petstore-expanded/gin/petstore_test.go b/examples/petstore-expanded/gin/petstore_test.go
index 01fc944..ccb38de 100644
--- a/examples/petstore-expanded/gin/petstore_test.go
+++ b/examples/petstore-expanded/gin/petstore_test.go
@@ -35,7 +35,7 @@ func TestPetStore(t *testing.T) {
 
 		var resultPet api.Pet
 		err = json.NewDecoder(rr.Body).Decode(&resultPet)
-		assert.NoError(t, err, "error unmarshalling response")
+		assert.NoError(t, err, "error unmarshaling response")
 		assert.Equal(t, newPet.Name, resultPet.Name)
 		assert.Equal(t, *newPet.Tag, *resultPet.Tag)
 	})
@@ -119,7 +119,7 @@ func TestPetStore(t *testing.T) {
 
 		var petError api.Error
 		err = json.NewDecoder(rr.Body).Decode(&petError)
-		assert.NoError(t, err, "error unmarshalling PetError")
+		assert.NoError(t, err, "error unmarshaling PetError")
 		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
 
 		// Now, delete both real pets
diff --git a/examples/petstore-expanded/gorilla/petstore_test.go b/examples/petstore-expanded/gorilla/petstore_test.go
index b0b52b3..c60afbc 100644
--- a/examples/petstore-expanded/gorilla/petstore_test.go
+++ b/examples/petstore-expanded/gorilla/petstore_test.go
@@ -53,7 +53,7 @@ func TestPetStore(t *testing.T) {
 
 		var resultPet api.Pet
 		err = json.NewDecoder(rr.Body).Decode(&resultPet)
-		assert.NoError(t, err, "error unmarshalling response")
+		assert.NoError(t, err, "error unmarshaling response")
 		assert.Equal(t, newPet.Name, resultPet.Name)
 		assert.Equal(t, *newPet.Tag, *resultPet.Tag)
 	})
@@ -146,7 +146,7 @@ func TestPetStore(t *testing.T) {
 
 		var petError api.Error
 		err = json.NewDecoder(rr.Body).Decode(&petError)
-		assert.NoError(t, err, "error unmarshalling PetError")
+		assert.NoError(t, err, "error unmarshaling PetError")
 		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
 
 		// Now, delete both real pets
diff --git a/examples/petstore-expanded/strict/petstore_test.go b/examples/petstore-expanded/strict/petstore_test.go
index 4cbfee0..34891e0 100644
--- a/examples/petstore-expanded/strict/petstore_test.go
+++ b/examples/petstore-expanded/strict/petstore_test.go
@@ -53,7 +53,7 @@ func TestPetStore(t *testing.T) {
 
 		var resultPet api.Pet
 		err = json.NewDecoder(rr.Body).Decode(&resultPet)
-		assert.NoError(t, err, "error unmarshalling response")
+		assert.NoError(t, err, "error unmarshaling response")
 		assert.Equal(t, newPet.Name, resultPet.Name)
 		assert.Equal(t, *newPet.Tag, *resultPet.Tag)
 	})
@@ -146,7 +146,7 @@ func TestPetStore(t *testing.T) {
 
 		var petError api.Error
 		err = json.NewDecoder(rr.Body).Decode(&petError)
-		assert.NoError(t, err, "error unmarshalling PetError")
+		assert.NoError(t, err, "error unmarshaling PetError")
 		assert.Equal(t, int32(http.StatusNotFound), petError.Code)
 
 		// Now, delete both real pets
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index be29e17..adaaaee 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -131,6 +131,9 @@ type AdditionalPropertiesObject5 map[string]SchemaObject
 // AdditionalPropertiesObject6 Array of object with additional properties
 type AdditionalPropertiesObject6 = []map[string]SchemaObject
 
+// AdditionalPropertiesObject7 Has additional properties with schema for dictionaries
+type AdditionalPropertiesObject7 map[string]*SchemaObjectNullable
+
 // AnyOfObject1 simple anyOf case
 type AnyOfObject1 struct {
 	union json.RawMessage
@@ -250,7 +253,7 @@ type OneOfObject3_Union struct {
 	union json.RawMessage
 }
 
-// OneOfObject4 oneOf plus fixed type - custom marshaling/unmarshalling
+// OneOfObject4 oneOf plus fixed type - custom marshaling/unmarshaling
 type OneOfObject4 struct {
 	FixedProperty *string `json:"fixedProperty,omitempty"`
 	union         json.RawMessage
@@ -347,6 +350,17 @@ type SchemaObject struct {
 	WriteOnlyRequiredProp *int    `json:"writeOnlyRequiredProp,omitempty"`
 }
 
+// SchemaObjectNullable defines model for SchemaObjectNullable.
+type SchemaObjectNullable struct {
+	FirstName string `json:"firstName"`
+
+	// ReadOnlyRequiredProp This property is required and readOnly, so the go model should have it as a pointer,
+	// as it will not be included when it is sent from client to server.
+	ReadOnlyRequiredProp  *string `json:"readOnlyRequiredProp,omitempty"`
+	Role                  string  `json:"role"`
+	WriteOnlyRequiredProp *int    `json:"writeOnlyRequiredProp,omitempty"`
+}
+
 // OneOfVariant51 defines model for one_of_variant51.
 type OneOfVariant51 struct {
 	Discriminator string `json:"discriminator"`
@@ -458,7 +472,7 @@ func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error {
 			var fieldVal interface{}
 			err := json.Unmarshal(fieldBuf, &fieldVal)
 			if err != nil {
-				return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
 			}
 			a.AdditionalProperties[fieldName] = fieldVal
 		}
@@ -545,7 +559,7 @@ func (a *AdditionalPropertiesObject1) UnmarshalJSON(b []byte) error {
 			var fieldVal int
 			err := json.Unmarshal(fieldBuf, &fieldVal)
 			if err != nil {
-				return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
 			}
 			a.AdditionalProperties[fieldName] = fieldVal
 		}
@@ -623,7 +637,7 @@ func (a *AdditionalPropertiesObject3) UnmarshalJSON(b []byte) error {
 			var fieldVal interface{}
 			err := json.Unmarshal(fieldBuf, &fieldVal)
 			if err != nil {
-				return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
 			}
 			a.AdditionalProperties[fieldName] = fieldVal
 		}
@@ -697,7 +711,7 @@ func (a *AdditionalPropertiesObject4) UnmarshalJSON(b []byte) error {
 			var fieldVal interface{}
 			err := json.Unmarshal(fieldBuf, &fieldVal)
 			if err != nil {
-				return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
 			}
 			a.AdditionalProperties[fieldName] = fieldVal
 		}
@@ -768,7 +782,7 @@ func (a *AdditionalPropertiesObject4_Inner) UnmarshalJSON(b []byte) error {
 			var fieldVal interface{}
 			err := json.Unmarshal(fieldBuf, &fieldVal)
 			if err != nil {
-				return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
 			}
 			a.AdditionalProperties[fieldName] = fieldVal
 		}
diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml
index 24fdf77..f755a6a 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -137,7 +137,7 @@ components:
           type: string
         readOnlyRequiredProp:
           description: |
-            This property is required and readOnly, so the go model should have it as a pointer, 
+            This property is required and readOnly, so the go model should have it as a pointer,
             as it will not be included when it is sent from client to server.
           type: string
           readOnly: true
@@ -149,6 +149,27 @@ components:
         - firstName
         - readOnlyRequiredProp
         - writeOnlyRequiredProp
+    SchemaObjectNullable:
+      properties:
+        role:
+          type: string
+        firstName:
+          type: string
+        readOnlyRequiredProp:
+          description: |
+            This property is required and readOnly, so the go model should have it as a pointer,
+            as it will not be included when it is sent from client to server.
+          type: string
+          readOnly: true
+        writeOnlyRequiredProp:
+          type: integer
+          writeOnly: true
+      required:
+        - role
+        - firstName
+        - readOnlyRequiredProp
+        - writeOnlyRequiredProp
+      nullable: true
     AdditionalPropertiesObject1:
       description: Has additional properties of type int
       type: object
@@ -207,6 +228,11 @@ components:
         type: object
         additionalProperties:
           $ref: '#/components/schemas/SchemaObject'
+    AdditionalPropertiesObject7:
+      description: Has additional properties with schema for dictionaries
+      type: object
+      additionalProperties:
+        $ref: '#/components/schemas/SchemaObjectNullable'
     OneOfObject1:
       description: oneOf with references and no discriminator
       oneOf:
@@ -234,7 +260,7 @@ components:
             - $ref: '#/components/schemas/OneOfVariant2'
             - $ref: '#/components/schemas/OneOfVariant3'
     OneOfObject4:
-      description: oneOf plus fixed type - custom marshaling/unmarshalling
+      description: oneOf plus fixed type - custom marshaling/unmarshaling
       type: object
       properties:
         fixedProperty:
diff --git a/internal/test/components/components_test.go b/internal/test/components/components_test.go
index 7810ea2..268612a 100644
--- a/internal/test/components/components_test.go
+++ b/internal/test/components/components_test.go
@@ -14,7 +14,7 @@ func assertJsonEqual(t *testing.T, j1 []byte, j2 []byte) {
 }
 
 func TestRawJSON(t *testing.T) {
-	// Check raw json unmarshalling
+	// Check raw json unmarshaling
 	const buf = `{"name":"bob","value1":{"present":true}}`
 	var dst ObjectWithJsonField
 	err := json.Unmarshal([]byte(buf), &dst)
@@ -52,7 +52,7 @@ func TestAdditionalProperties(t *testing.T) {
 	assert.True(t, found)
 	assert.EqualValues(t, 7, foo)
 
-	// test that additionalProperties that reference a schema work when unmarshalling
+	// test that additionalProperties that reference a schema work when unmarshaling
 	bossSchema := SchemaObject{
 		FirstName: "bob",
 		Role:      "warehouse manager",
@@ -63,6 +63,20 @@ func TestAdditionalProperties(t *testing.T) {
 	err = json.Unmarshal([]byte(buf2), &obj5)
 	assert.NoError(t, err)
 	assert.Equal(t, bossSchema, obj5["boss"])
+
+	bossSchemaNullable := &SchemaObjectNullable{
+		FirstName: "bob",
+		Role:      "warehouse manager",
+	}
+
+	buf3 := `{"boss": { "firstName": "bob", "role": "warehouse manager" }, "employee": null}`
+	var obj7 AdditionalPropertiesObject7
+	err = json.Unmarshal([]byte(buf3), &obj7)
+	assert.NoError(t, err)
+	employee, ok := obj7["employee"]
+	assert.True(t, ok)
+	assert.Equal(t, bossSchemaNullable, obj7["boss"])
+	assert.Nil(t, employee)
 }
 
 func TestOneOf(t *testing.T) {
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index c077475..31ee2bb 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -445,7 +445,7 @@ func (w *ServerInterfaceWrapper) GetPet(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter petId: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetPet(ctx, petId)
 	return err
 }
@@ -454,7 +454,7 @@ func (w *ServerInterfaceWrapper) GetPet(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) ValidatePets(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.ValidatePets(ctx)
 	return err
 }
diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index d3f1a23..fb3b38b 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -270,7 +270,7 @@ type ServerInterfaceWrapper struct {
 func (w *ServerInterfaceWrapper) ExampleGet(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.ExampleGet(ctx)
 	return err
 }
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index b9904fc..775e9a3 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -323,7 +323,7 @@ func (w *ServerInterfaceWrapper) GetFoo(ctx echo.Context) error {
 		params.Bar = &Bar
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetFoo(ctx, params)
 	return err
 }
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
index 703c262..6e5994e 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
@@ -3,37 +3,9 @@
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
 package headdigitofhttpheader
 
-import (
-	"context"
-	"fmt"
-	"net/http"
-)
-
 type N200ResponseHeaders struct {
 	N000Foo string
 }
 type N200Response struct {
 	Headers N200ResponseHeaders
 }
-
-type GetFooRequestObject struct {
-}
-
-type GetFooResponseObject interface {
-	VisitGetFooResponse(w http.ResponseWriter) error
-}
-
-type GetFoo200Response = N200Response
-
-func (response GetFoo200Response) VisitGetFooResponse(w http.ResponseWriter) error {
-	w.Header().Set("000-foo", fmt.Sprint(response.Headers.N000Foo))
-	w.WriteHeader(200)
-	return nil
-}
-
-// StrictServerInterface represents all server handlers.
-type StrictServerInterface interface {
-
-	// (GET /foo)
-	GetFoo(ctx context.Context, request GetFooRequestObject) (GetFooResponseObject, error)
-}
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
index 1760746..4a5d3e8 100644
--- a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
@@ -2,22 +2,3 @@
 //
 // Code generated by github.com/deepmap/oapi-codegen version (devel) DO NOT EDIT.
 package head_digit_of_operation_id
-
-import (
-	"context"
-	"net/http"
-)
-
-type N3GPPFooRequestObject struct {
-}
-
-type N3GPPFooResponseObject interface {
-	VisitN3GPPFooResponse(w http.ResponseWriter) error
-}
-
-// StrictServerInterface represents all server handlers.
-type StrictServerInterface interface {
-
-	// (GET /3gpp/foo)
-	N3GPPFoo(ctx context.Context, request N3GPPFooRequestObject) (N3GPPFooResponseObject, error)
-}
diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
index 3f0d8e0..65d6646 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -273,7 +273,7 @@ type ServerInterfaceWrapper struct {
 func (w *ServerInterfaceWrapper) GetFoo(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetFoo(ctx)
 	return err
 }
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
index 69766e1..11247c7 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
@@ -86,16 +86,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
index ed5a474..53c506d 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
@@ -57,16 +57,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go
index 1f2b4b8..3e17838 100644
--- a/internal/test/parameters/parameters.gen.go
+++ b/internal/test/parameters/parameters.gen.go
@@ -2752,10 +2752,10 @@ func (w *ServerInterfaceWrapper) GetContentObject(ctx echo.Context) error {
 
 	err = json.Unmarshal([]byte(ctx.Param("param")), &param)
 	if err != nil {
-		return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter 'param' as JSON")
+		return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'param' as JSON")
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetContentObject(ctx, param)
 	return err
 }
@@ -2843,7 +2843,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error {
 		}
 		err = json.Unmarshal([]byte(decoded), &value)
 		if err != nil {
-			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter 'co' as JSON")
+			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
 		}
 		params.Co = &value
 
@@ -2860,7 +2860,7 @@ func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error {
 
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetCookie(ctx, params)
 	return err
 }
@@ -2878,7 +2878,7 @@ func (w *ServerInterfaceWrapper) EnumParams(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter enumPathParam: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.EnumParams(ctx, params)
 	return err
 }
@@ -2991,7 +2991,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error {
 
 		err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
 		if err != nil {
-			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter 'X-Complex-Object' as JSON")
+			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'X-Complex-Object' as JSON")
 		}
 
 		params.XComplexObject = &XComplexObject
@@ -3012,7 +3012,7 @@ func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error {
 		params.N1StartingWithNumber = &N1StartingWithNumber
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetHeader(ctx, params)
 	return err
 }
@@ -3028,7 +3028,7 @@ func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetLabelExplodeArray(ctx, param)
 	return err
 }
@@ -3044,7 +3044,7 @@ func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetLabelExplodeObject(ctx, param)
 	return err
 }
@@ -3060,7 +3060,7 @@ func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetLabelNoExplodeArray(ctx, param)
 	return err
 }
@@ -3076,7 +3076,7 @@ func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetLabelNoExplodeObject(ctx, param)
 	return err
 }
@@ -3092,7 +3092,7 @@ func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetMatrixExplodeArray(ctx, id)
 	return err
 }
@@ -3108,7 +3108,7 @@ func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetMatrixExplodeObject(ctx, id)
 	return err
 }
@@ -3124,7 +3124,7 @@ func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetMatrixNoExplodeArray(ctx, id)
 	return err
 }
@@ -3140,7 +3140,7 @@ func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx echo.Context) erro
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetMatrixNoExplodeObject(ctx, id)
 	return err
 }
@@ -3153,7 +3153,7 @@ func (w *ServerInterfaceWrapper) GetPassThrough(ctx echo.Context) error {
 
 	param = ctx.Param("param")
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetPassThrough(ctx, param)
 	return err
 }
@@ -3171,7 +3171,7 @@ func (w *ServerInterfaceWrapper) GetDeepObject(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter deepObj: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetDeepObject(ctx, params)
 	return err
 }
@@ -3238,7 +3238,7 @@ func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error {
 		var value ComplexObject
 		err = json.Unmarshal([]byte(paramValue), &value)
 		if err != nil {
-			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshalling parameter 'co' as JSON")
+			return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
 		}
 		params.Co = &value
 
@@ -3251,7 +3251,7 @@ func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetQueryForm(ctx, params)
 	return err
 }
@@ -3267,7 +3267,7 @@ func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetSimpleExplodeArray(ctx, param)
 	return err
 }
@@ -3283,7 +3283,7 @@ func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetSimpleExplodeObject(ctx, param)
 	return err
 }
@@ -3299,7 +3299,7 @@ func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx echo.Context) error
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetSimpleNoExplodeArray(ctx, param)
 	return err
 }
@@ -3315,7 +3315,7 @@ func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx echo.Context) erro
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetSimpleNoExplodeObject(ctx, param)
 	return err
 }
@@ -3331,7 +3331,7 @@ func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetSimplePrimitive(ctx, param)
 	return err
 }
@@ -3344,7 +3344,7 @@ func (w *ServerInterfaceWrapper) GetStartingWithNumber(ctx echo.Context) error {
 
 	n1param = ctx.Param("1param")
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetStartingWithNumber(ctx, n1param)
 	return err
 }
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index f701c28..6f7bb7c 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -189,6 +189,9 @@ type ClientInterface interface {
 	// EnsureEverythingIsReferenced request
 	EnsureEverythingIsReferenced(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 
+	// Issue1051 request
+	Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
 	// Issue127 request
 	Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 
@@ -230,6 +233,18 @@ func (c *Client) EnsureEverythingIsReferenced(ctx context.Context, reqEditors ..
 	return c.Client.Do(req)
 }
 
+func (c *Client) Issue1051(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+	req, err := NewIssue1051Request(c.Server)
+	if err != nil {
+		return nil, err
+	}
+	req = req.WithContext(ctx)
+	if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+		return nil, err
+	}
+	return c.Client.Do(req)
+}
+
 func (c *Client) Issue127(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
 	req, err := NewIssue127Request(c.Server)
 	if err != nil {
@@ -377,6 +392,33 @@ func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error
 	return req, nil
 }
 
+// NewIssue1051Request generates requests for Issue1051
+func NewIssue1051Request(server string) (*http.Request, error) {
+	var err error
+
+	serverURL, err := url.Parse(server)
+	if err != nil {
+		return nil, err
+	}
+
+	operationPath := fmt.Sprintf("/issues/1051")
+	if operationPath[0] == '/' {
+		operationPath = "." + operationPath
+	}
+
+	queryURL, err := serverURL.Parse(operationPath)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http.NewRequest("GET", queryURL.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return req, nil
+}
+
 // NewIssue127Request generates requests for Issue127
 func NewIssue127Request(server string) (*http.Request, error) {
 	var err error
@@ -704,6 +746,9 @@ type ClientWithResponsesInterface interface {
 	// EnsureEverythingIsReferenced request
 	EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error)
 
+	// Issue1051 request
+	Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error)
+
 	// Issue127 request
 	Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error)
 
@@ -763,6 +808,29 @@ func (r EnsureEverythingIsReferencedResponse) StatusCode() int {
 	return 0
 }
 
+type Issue1051Response struct {
+	Body                             []byte
+	HTTPResponse                     *http.Response
+	JSON200                          *map[string]interface{}
+	ApplicationvndSomethingV1JSON200 *map[string]interface{}
+}
+
+// Status returns HTTPResponse.Status
+func (r Issue1051Response) Status() string {
+	if r.HTTPResponse != nil {
+		return r.HTTPResponse.Status
+	}
+	return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r Issue1051Response) StatusCode() int {
+	if r.HTTPResponse != nil {
+		return r.HTTPResponse.StatusCode
+	}
+	return 0
+}
+
 type Issue127Response struct {
 	Body         []byte
 	HTTPResponse *http.Response
@@ -946,6 +1014,15 @@ func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx conte
 	return ParseEnsureEverythingIsReferencedResponse(rsp)
 }
 
+// Issue1051WithResponse request returning *Issue1051Response
+func (c *ClientWithResponses) Issue1051WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue1051Response, error) {
+	rsp, err := c.Issue1051(ctx, reqEditors...)
+	if err != nil {
+		return nil, err
+	}
+	return ParseIssue1051Response(rsp)
+}
+
 // Issue127WithResponse request returning *Issue127Response
 func (c *ClientWithResponses) Issue127WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*Issue127Response, error) {
 	rsp, err := c.Issue127(ctx, reqEditors...)
@@ -1068,6 +1145,32 @@ func ParseEnsureEverythingIsReferencedResponse(rsp *http.Response) (*EnsureEvery
 	return response, nil
 }
 
+// ParseIssue1051Response parses an HTTP response from a Issue1051WithResponse call
+func ParseIssue1051Response(rsp *http.Response) (*Issue1051Response, error) {
+	bodyBytes, err := io.ReadAll(rsp.Body)
+	defer func() { _ = rsp.Body.Close() }()
+	if err != nil {
+		return nil, err
+	}
+
+	response := &Issue1051Response{
+		Body:         bodyBytes,
+		HTTPResponse: rsp,
+	}
+
+	switch {
+	case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+		var dest map[string]interface{}
+		if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+			return nil, err
+		}
+		response.ApplicationvndSomethingV1JSON200 = &dest
+
+	}
+
+	return response, nil
+}
+
 // ParseIssue127Response parses an HTTP response from a Issue127WithResponse call
 func ParseIssue127Response(rsp *http.Response) (*Issue127Response, error) {
 	bodyBytes, err := io.ReadAll(rsp.Body)
@@ -1259,6 +1362,9 @@ type ServerInterface interface {
 	// (GET /ensure-everything-is-referenced)
 	EnsureEverythingIsReferenced(ctx echo.Context) error
 
+	// (GET /issues/1051)
+	Issue1051(ctx echo.Context) error
+
 	// (GET /issues/127)
 	Issue127(ctx echo.Context) error
 
@@ -1295,18 +1401,29 @@ func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context)
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.EnsureEverythingIsReferenced(ctx)
 	return err
 }
 
+// Issue1051 converts echo context to params.
+func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error {
+	var err error
+
+	ctx.Set(Access_tokenScopes, []string{})
+
+	// Invoke the callback with all the unmarshalled arguments
+	err = w.Handler.Issue1051(ctx)
+	return err
+}
+
 // Issue127 converts echo context to params.
 func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error {
 	var err error
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue127(ctx)
 	return err
 }
@@ -1317,7 +1434,7 @@ func (w *ServerInterfaceWrapper) Issue185(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue185(ctx)
 	return err
 }
@@ -1335,7 +1452,7 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue209(ctx, str)
 	return err
 }
@@ -1353,7 +1470,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue30(ctx, pFallthrough)
 	return err
 }
@@ -1364,7 +1481,7 @@ func (w *ServerInterfaceWrapper) GetIssues375(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.GetIssues375(ctx)
 	return err
 }
@@ -1382,7 +1499,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue41(ctx, n1param)
 	return err
 }
@@ -1402,7 +1519,7 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error {
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter foo: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue9(ctx, params)
 	return err
 }
@@ -1413,7 +1530,7 @@ func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error {
 
 	ctx.Set(Access_tokenScopes, []string{})
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.Issue975(ctx)
 	return err
 }
@@ -1447,6 +1564,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
 	}
 
 	router.GET(baseURL+"/ensure-everything-is-referenced", wrapper.EnsureEverythingIsReferenced)
+	router.GET(baseURL+"/issues/1051", wrapper.Issue1051)
 	router.GET(baseURL+"/issues/127", wrapper.Issue127)
 	router.GET(baseURL+"/issues/185", wrapper.Issue185)
 	router.GET(baseURL+"/issues/209/$:str", wrapper.Issue209)
@@ -1461,31 +1579,32 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
 // Base64 encoded, gzipped, json marshaled Swagger object
 var swaggerSpec = []string{
 
-	"H4sIAAAAAAAC/7RYT2/buBL/KixfgXexLdtp0ca3vL5u4QW2CZoseqhzoMWxxUYaqiRlRzD03RdDypZd",
-	"SW6zaXOJJHJmfvOHv+F4x2Od5RoBneWzHc+FERk4MP7t1hmF6zneCJfQuwQbG5U7pZHP+BWzfp3lwiXs",
-	"IMkHXNEyfeUDjiIDPuPW0YKBb4UyIPnMmQIG3MYJZIJUuzKvtylc86qq9oseyOtbJ4yzn5VLPhbZEkwb",
-	"zV2iLAsijGwy60XYVrmECYZBbLA3pJdfIXa8GvArLO/KHCZ8tmveph3u1ivMQG7AUsSYwJKRwtECFxgQ",
-	"JLpIJVsCE8gUOjArEcOuWiDZeldYp7MQ1jsPZMdX2mTC8RmP/WIDsY7FgD8OtcjVMNYS1oBDeHRGDJ1Y",
-	"2yCu+YwvheEUs/8Ttlg4kDdG52Bc6bManhV4CYQtLbY9/NsCc+QE6u2LFo5qwHXq1U6C6N7SPpl926fd",
-	"209tzx0rLEjmNJM6oBAomUuEO4Pk4meQUACbPUMDwh7c/RhiwRRaB0K+ONL96lfDfhqO6vi0fDkk7QCP",
-	"33fU8nsssjleL7/O8coY4ZOvHGS2XQUbkdI/wCIj/StlLEG2EGuUR8oPJ7LDXP1BeFPVgH8ABKPi67Ch",
-	"OdWNxMciTcUyhZsTLKfItA9ugNdOfL14hXKvy9f04bmnFptY7voXn6b0uwwdnrv1daXrunBgiAeI2K5Q",
-	"Y5npws4RA8GdhkX1fD52iQhnDaaFTcm2fSrHtR7Sx2FN0t7yJ6A3eYBzfYAbdu1+EAe/a1DDbXtd+Ror",
-	"jHLlLbF18ELEMVg7dPoBkN6XIAyYP/bU+Ofnu2HgSRZ2Mr9ztEBe9wkyEYSac5c4l4dWonClO1oGWMdi",
-	"YcGylTZsI4zShWXK2sJ/KlAyvQHDnMpgxG5SEBaYkJIJ5vayJLpAagTLYs1W6hFkgOWUo9IJVm7BbDy0",
-	"DRgbrE9G49E4lDSgyBWf8YvReDThA986fVgiQFsYGMIGTOkSheuhskMDKzCAcajmNbiebggoc63QMXhU",
-	"1llmtScm1rR8FgukXhUbIE5iCj2HLdDmEHsmQ+1oQ24KBOn9ouITZGYu+Yy/9wDfH/DN7acGHRWGzTXa",
-	"kOTpeEz/Yo0O0IMWeZ6q2GuLvno23B3dCU4LXTR9mr80sOIz/p+ocSWqrwvRoZ9Xg73M9CdlpiQTd/To",
-	"c7Ktnt5BleFvwKNQW9Fk+qY3dX+JB2AUVFagLfJcG8qMD9qj87cNy6TG/zqWG4Asd6zZ5VdHHWmak12y",
-	"+syUnAvEKfuTu8e6HrP0OarI+SgT5kHqLT5bUSmeg4bUSFiJInW/MXi/yOPvK+/t637SKHNga5L3HrBt",
-	"Asj2DTfaczxrjiUTBti+S/aX3dvXdU8E6/6nZfnLgtZxmwjeHtU4wTsOwHR8Gb3cWWeq3ji8SyB+sEyt",
-	"mqEmuCohTkUTgrTsdng6vuRtDIOT4epLt2fNluhk+Kruj1y4GEe7lUhTlxhdrJOq7cEnsNRwJHuAcquN",
-	"PJ5LcgO+SxHZU8ujAPqJqSaOOiQdfl2Mf8atjuHvCOyThsATp9/0Fy5de+vk1JUr7L6QiRW3KgZKp0uA",
-	"0YXXryukES0w9AK3iYqT+rtVEphe0bK/2nZV9gdwPiaWcP1GUm3d6Fsn+tUk2k18Dvor+mafoqPRmCZ3",
-	"PxwfRuOOlL8K15EfJTjYP5vbc062x/uquj97ii/7D2+qAF04udY3RKYw1sZA7NKSntNCgvQ3vpqTQhiW",
-	"WpZ05Vlg428vp132hOVbAaY8Knytn1bw/5on66Z0HInrmrm9Z/w8K16eOV3NbwpspSBtyGQNjomaC+lS",
-	"mQG63oD93mPS8btHR0T8L1ZFXCdctvzynzfClHQ2UthASjQgdVyQax4Xr0/ffobxqT+dXr7cUx49Adel",
-	"UZi0HkdmUVRf92mAGEmAPBP5SChi+H8CAAD//wmLy+yNEwAA",
+	"H4sIAAAAAAAC/7RYXW/buBL9Kyxvgftw/Z0GbfyW2+0WLrBJ0GTRhzoPtDi22EhDlaTsCIb++2JI2bIj",
+	"yW02bV5iiZzhmTPDM6S2PNJpphHQWT7d8kwYkYID459unVG4muGNcDE9S7CRUZlTGvmUXzLrx1kmXMz2",
+	"lrzHFQ3TW97jKFLgU24dDRj4nisDkk+dyaHHbRRDKsi1K7JqmsIVL8tyN+iBnN86YZz9olx8lacLME00",
+	"d7GyLJgwWpNZb8I2ysVMMAxmvd1CevENIsfLHr/E4q7IYMyn2/pp0hJuNcIMZAYsMcYEFowcDuY4x4Ag",
+	"1nki2QKYQKbQgVmKCLblHGmt97l1Og203nkgW77UJhWOT3nkB2uIFRc9/tjXIlP9SEtYAfbh0RnRd2Jl",
+	"g7nmU74QhhNnfxC2SDiQN0ZnYFzhsxp+K/AWCBsabEb4twXmKAjUm1cNHGWP68S7HQfT3Uq7ZHZNn7RP",
+	"P1575lhuQTKnmdQBhUDJXCzcCSRnP4OECKzn9A0Iuw/3KnDBFFoHQr468P3mV8N+Ho7ycLd83SdtD4/f",
+	"t9TyB8zTGV4vvs3w0hjhk68cpLZZBWuR0D/APCX/S2UsQbYQaZQHzvc7smW56oXwS5U9/hEQjIquw4R6",
+	"V9cWV3mSiEUCN0dYjpFpT26A10x8NXiJcufL1/T+d0ct1lxuuwef5/RJhva/2/21pes6d2BIB0jYLlFj",
+	"kerczhCDwB3TojpeH4ZEgrMC08CmZHN9KseV7tPLfiXSfuXPQE9yD+d6DzfM2v6ABz+rV8FtRl36GsuN",
+	"csUtqXWIQkQRWNt3+gGQnhcgDJg/d9L46ctdP+gkCzOZnzmYI6/6BC0RjOp9FzuXhVaicKlbWgZYxyJh",
+	"wbKlNmwtjNK5Zcra3L/KUTK9BsOcSmHAbhIQFpiQkgnmdrZkOkdqBIt8xZbqEWSA5ZSj0gmr3IJZe2hr",
+	"MDasPh6MBqNQ0oAiU3zKzwajwZj3fOv0tAwBbW6gD2swhYsVrvrK9g0swQBGoZpX4Dq6IaDMtELH4FFZ",
+	"Z5nVXphY3fJZJJB6VWSANIkp9Bo2R5tB5JUMtaMJmckRpI+Lik/QMjPJp/yDB/hhj29mP9foqDBsptGG",
+	"JE9GI/oXaXSAHrTIskRF3tvwm1fD7cGZ4LjQRd2n+WsDSz7l/xnWoQyr48Jw38/L3s5m8pM2E7KJWnr0",
+	"KdtGT2+RyvDX48NQW8Px6Hzcmbu/8sSpLAGWglTCny8sI9KEQvbp9vqqJQ0z8uu9vpDz5m49nL9GObA6",
+	"BZ/qwXr8vx87eBr55G134OIBGJUTy9HmWaYN1aSH/ugqHqTG/zqWGYA0c6ye5UcHncxM3r6UmFMlcNz3",
+	"npL2mCYvcUXBD1NhHqTe4IsdFeIlaMiNhKXIE/cbyftFET+tvHfn3XJZZMBWZO8jYJsYkO2OGsNdd2O1",
+	"IDFhgO3OB91l9+68Og2Adf/XsvhlpLWco0K0BzVO8A4JmIwuhq+31pmyk4f3MUQPlqllfZ0LoUqIElFT",
+	"kBTtAU9GF7yJoXd0rfzaHlk9ZXh07SzvD0I4Gw23S5EkLjY6X8VlM4LPYKnVSvYAxUYbeXgjywz4/kxt",
+	"jpo9EejvipVwVJS0xHU2+pmwWq69B2Cfdf09Cvptd+HSgb9KTlW5wu4KmVRxoyKgdLoYGB31/bhCupwG",
+	"hZ7jJlZRXL23SgLTSxr2h/q2yv4IznNiCddvFNXGXaaxo9+Mh9uxz0F3Rd/sUnTwUUDhKnwW2H8UaEn5",
+	"m3AQ+1GCw/onc3sqyOaHjbK8P7mLL7o3b6IAXdi51jdEpjDSxkDkkoJ+J7kE6c+6lSYFGhZaFnTYm2Md",
+	"b6emXXTQ8j0HUxwUvtbPK/h/rZNVUzpk4rpSbh8ZP62KFyd2V/01hS0VJLWYrMAxUWkhHadTQNdJ2O/d",
+	"Ji1ffFoY8d/q8qhKuGzE5V+vhSlobySwhoRkQOoop9A8Ll7tvt3tzaf++N729Z7y6AW4Ko3cJNVFbDoc",
+	"VhcdujoNJECWimwgFCn8PwEAAP//WUiKvIcUAAA=",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/schemas/schemas.yaml b/internal/test/schemas/schemas.yaml
index c93e1f4..2e094de 100644
--- a/internal/test/schemas/schemas.yaml
+++ b/internal/test/schemas/schemas.yaml
@@ -133,7 +133,20 @@ paths:
             application/json:
               schema:
                 $ref: "#/components/schemas/DeprecatedProperty"
-
+  /issues/1051:
+    get:
+      operationId: Issue1051
+      description: |
+        Multiple media types contain JSON
+      responses:
+        '200':
+          content:
+            application/vnd.something.v1+json:
+              schema:
+                type: object
+            application/json:
+              schema:
+                type: object
 components:
   schemas:
     GenericObject:
diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go
index d43de70..d676d16 100644
--- a/internal/test/server/server.gen.go
+++ b/internal/test/server/server.gen.go
@@ -458,16 +458,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go
index b3904b5..d3190ec 100644
--- a/internal/test/strict-server/chi/server.gen.go
+++ b/internal/test/strict-server/chi/server.gen.go
@@ -288,16 +288,16 @@ func (e *UnescapedCookieParamError) Unwrap() error {
 	return e.Err
 }
 
-type UnmarshallingParamError struct {
+type UnmarshalingParamError struct {
 	ParamName string
 	Err       error
 }
 
-func (e *UnmarshallingParamError) Error() string {
-	return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+func (e *UnmarshalingParamError) Error() string {
+	return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
 }
 
-func (e *UnmarshallingParamError) Unwrap() error {
+func (e *UnmarshalingParamError) Unwrap() error {
 	return e.Err
 }
 
@@ -1267,18 +1267,18 @@ var swaggerSpec = []string{
 	"Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
 	"DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
 	"eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
-	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
-	"33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
-	"0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
-	"3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
-	"FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
-	"QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
-	"Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
-	"fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
-	"5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
-	"MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
-	"qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
-	"AP//O0NNuucUAAA=",
+	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uShAMqXJeBerjNyIt5awDfwvstN+",
+	"31Hps6ZNoHdGLs+RMG1ebqXz9Xj8SnnZRPwmGBvCWDuVbBVYCzMTVTHA+Wf9VZtaM0A02O0sKauClBVI",
+	"27HaZfv3XuQ5lK/xkpnBMpaCxJlYP5WlixLf9YLBGrmbm9qxuakZGSZBFKxWNGe94jfFrTQTzCmdF8B6",
+	"p6LBSBbQtdyftJx0e7n3GGevpWgH5TGu6zpug1dhATozEuTLYFUpckisznfVPbYgnvLpknza7jfXEyVR",
+	"xAkeKbGFUPrwyfFK7eQ70ycr7FCuCO2JKOPcxF9hWRuUsRUoSiBAl6y89cYD5zBQyn+uJVkmNJsC06IE",
+	"ycSMANkHwzpIt1eyk87uB/MxiGyg2uN2/ZH+teKekvYI5hH3BngaWAl1rdAHnbCC6ABtD/+an/8pAD2b",
+	"YdCLd0wNt8G+Ra2pQ5g53xKHIjfAX7A02ZK4zMBwOOP2Rt/XOIN8JJ8+9+/h8VlH/glb32vX9rGEVWHx",
+	"ac46refQ9sJO+gwWF0qCSUp7cyTyxUh1FjI1UyDjbhdx8O2plnBrdIZAuyOQv05oQ2wN5m85NAcWGIiY",
+	"M6wGVlaOmBXOMUVtFylUuClJ2Gsenzee3QZL95t2eiiqb84U0zeXiujN+Op4lbdnzpudUeaJepz89j7I",
+	"HHtfPNnMdOTEdzq7Fypnf0mJtx5Uhkv45yCwOdMzUAs/EWnJEKhCDZItlOgfAfZqswPYhHVoFgpubKah",
+	"/nHnmIEoOoh1zaNDD0AP/+PniXM+m507T5uIhxeukCwVFj6iRDZNkvAyNnK1yHPAkTKJsIo3D80/AQAA",
+	"///iKNcc5hQAAA==",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go
index 0912230..41b7b0e 100644
--- a/internal/test/strict-server/echo/server.gen.go
+++ b/internal/test/strict-server/echo/server.gen.go
@@ -65,7 +65,7 @@ type ServerInterfaceWrapper struct {
 func (w *ServerInterfaceWrapper) JSONExample(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.JSONExample(ctx)
 	return err
 }
@@ -74,7 +74,7 @@ func (w *ServerInterfaceWrapper) JSONExample(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) MultipartExample(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.MultipartExample(ctx)
 	return err
 }
@@ -83,7 +83,7 @@ func (w *ServerInterfaceWrapper) MultipartExample(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.MultipleRequestAndResponseTypes(ctx)
 	return err
 }
@@ -99,7 +99,7 @@ func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) e
 		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.ReservedGoKeywordParameters(ctx, pType)
 	return err
 }
@@ -108,7 +108,7 @@ func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) e
 func (w *ServerInterfaceWrapper) ReusableResponses(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.ReusableResponses(ctx)
 	return err
 }
@@ -117,7 +117,7 @@ func (w *ServerInterfaceWrapper) ReusableResponses(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) TextExample(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.TextExample(ctx)
 	return err
 }
@@ -126,7 +126,7 @@ func (w *ServerInterfaceWrapper) TextExample(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) UnknownExample(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.UnknownExample(ctx)
 	return err
 }
@@ -135,7 +135,7 @@ func (w *ServerInterfaceWrapper) UnknownExample(ctx echo.Context) error {
 func (w *ServerInterfaceWrapper) UnspecifiedContentType(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.UnspecifiedContentType(ctx)
 	return err
 }
@@ -144,7 +144,7 @@ func (w *ServerInterfaceWrapper) UnspecifiedContentType(ctx echo.Context) error
 func (w *ServerInterfaceWrapper) URLEncodedExample(ctx echo.Context) error {
 	var err error
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.URLEncodedExample(ctx)
 	return err
 }
@@ -190,7 +190,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx echo.Context) error {
 		params.Header2 = &Header2
 	}
 
-	// Invoke the callback with all the unmarshalled arguments
+	// Invoke the callback with all the unmarshaled arguments
 	err = w.Handler.HeadersExample(ctx, params)
 	return err
 }
@@ -1044,18 +1044,18 @@ var swaggerSpec = []string{
 	"Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
 	"DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
 	"eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
-	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
-	"33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
-	"0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
-	"3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
-	"FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
-	"QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
-	"Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
-	"fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
-	"5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
-	"MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
-	"qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
-	"AP//O0NNuucUAAA=",
+	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uShAMqXJeBerjNyIt5awDfwvstN+",
+	"31Hps6ZNoHdGLs+RMG1ebqXz9Xj8SnnZRPwmGBvCWDuVbBVYCzMTVTHA+Wf9VZtaM0A02O0sKauClBVI",
+	"27HaZfv3XuQ5lK/xkpnBMpaCxJlYP5WlixLf9YLBGrmbm9qxuakZGSZBFKxWNGe94jfFrTQTzCmdF8B6",
+	"p6LBSBbQtdyftJx0e7n3GGevpWgH5TGu6zpug1dhATozEuTLYFUpckisznfVPbYgnvLpknza7jfXEyVR",
+	"xAkeKbGFUPrwyfFK7eQ70ycr7FCuCO2JKOPcxF9hWRuUsRUoSiBAl6y89cYD5zBQyn+uJVkmNJsC06IE",
+	"ycSMANkHwzpIt1eyk87uB/MxiGyg2uN2/ZH+teKekvYI5hH3BngaWAl1rdAHnbCC6ABtD/+an/8pAD2b",
+	"YdCLd0wNt8G+Ra2pQ5g53xKHIjfAX7A02ZK4zMBwOOP2Rt/XOIN8JJ8+9+/h8VlH/glb32vX9rGEVWHx",
+	"ac46refQ9sJO+gwWF0qCSUp7cyTyxUh1FjI1UyDjbhdx8O2plnBrdIZAuyOQv05oQ2wN5m85NAcWGIiY",
+	"M6wGVlaOmBXOMUVtFylUuClJ2Gsenzee3QZL95t2eiiqb84U0zeXiujN+Op4lbdnzpudUeaJepz89j7I",
+	"HHtfPNnMdOTEdzq7Fypnf0mJtx5Uhkv45yCwOdMzUAs/EWnJEKhCDZItlOgfAfZqswPYhHVoFgpubKah",
+	"/nHnmIEoOoh1zaNDD0AP/+PniXM+m507T5uIhxeukCwVFj6iRDZNkvAyNnK1yHPAkTKJsIo3D80/AQAA",
+	"///iKNcc5hQAAA==",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/fiber/server.cfg.yaml b/internal/test/strict-server/fiber/server.cfg.yaml
new file mode 100644
index 0000000..3a64712
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.cfg.yaml
@@ -0,0 +1,6 @@
+package: api
+generate:
+  fiber-server: true
+  strict-server: true
+  embedded-spec: true
+output: server.gen.go
diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go
new file mode 100644
index 0000000..8467150
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.gen.go
@@ -0,0 +1,1105 @@
+// 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"
+	"context"
+	"encoding/base64"
+	"fmt"
+	"io"
+	"mime/multipart"
+	"net/http"
+	"net/url"
+	"path"
+	"strings"
+
+	"github.com/deepmap/oapi-codegen/pkg/runtime"
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/gofiber/fiber/v2"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+	// (POST /json)
+	JSONExample(c *fiber.Ctx) error
+
+	// (POST /multipart)
+	MultipartExample(c *fiber.Ctx) error
+
+	// (POST /multiple)
+	MultipleRequestAndResponseTypes(c *fiber.Ctx) error
+
+	// (GET /reserved-go-keyword-parameters/{type})
+	ReservedGoKeywordParameters(c *fiber.Ctx, pType string) error
+
+	// (POST /reusable-responses)
+	ReusableResponses(c *fiber.Ctx) error
+
+	// (POST /text)
+	TextExample(c *fiber.Ctx) error
+
+	// (POST /unknown)
+	UnknownExample(c *fiber.Ctx) error
+
+	// (POST /unspecified-content-type)
+	UnspecifiedContentType(c *fiber.Ctx) error
+
+	// (POST /urlencoded)
+	URLEncodedExample(c *fiber.Ctx) error
+
+	// (POST /with-headers)
+	HeadersExample(c *fiber.Ctx, params HeadersExampleParams) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+	Handler ServerInterface
+}
+
+type MiddlewareFunc fiber.Handler
+
+// JSONExample operation middleware
+func (siw *ServerInterfaceWrapper) JSONExample(c *fiber.Ctx) error {
+
+	return siw.Handler.JSONExample(c)
+}
+
+// MultipartExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartExample(c *fiber.Ctx) error {
+
+	return siw.Handler.MultipartExample(c)
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) error {
+
+	return siw.Handler.MultipleRequestAndResponseTypes(c)
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) error {
+
+	var err error
+
+	// ------------- Path parameter "type" -------------
+	var pType string
+
+	err = runtime.BindStyledParameter("simple", false, "type", c.Params("type"), &pType)
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter type: %w", err).Error())
+	}
+
+	return siw.Handler.ReservedGoKeywordParameters(c, pType)
+}
+
+// ReusableResponses operation middleware
+func (siw *ServerInterfaceWrapper) ReusableResponses(c *fiber.Ctx) error {
+
+	return siw.Handler.ReusableResponses(c)
+}
+
+// TextExample operation middleware
+func (siw *ServerInterfaceWrapper) TextExample(c *fiber.Ctx) error {
+
+	return siw.Handler.TextExample(c)
+}
+
+// UnknownExample operation middleware
+func (siw *ServerInterfaceWrapper) UnknownExample(c *fiber.Ctx) error {
+
+	return siw.Handler.UnknownExample(c)
+}
+
+// UnspecifiedContentType operation middleware
+func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *fiber.Ctx) error {
+
+	return siw.Handler.UnspecifiedContentType(c)
+}
+
+// URLEncodedExample operation middleware
+func (siw *ServerInterfaceWrapper) URLEncodedExample(c *fiber.Ctx) error {
+
+	return siw.Handler.URLEncodedExample(c)
+}
+
+// HeadersExample operation middleware
+func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
+
+	var err error
+
+	// Parameter object where we will unmarshal all parameters from the context
+	var params HeadersExampleParams
+
+	headers := c.GetReqHeaders()
+
+	// ------------- Required header parameter "header1" -------------
+	if value, found := headers[http.CanonicalHeaderKey("header1")]; found {
+		var Header1 string
+
+		err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, value, &Header1)
+		if err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error())
+		}
+
+		params.Header1 = Header1
+
+	} else {
+		err = fmt.Errorf("Header parameter header1 is required, but not found: %w", err)
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	}
+
+	// ------------- Optional header parameter "header2" -------------
+	if value, found := headers[http.CanonicalHeaderKey("header2")]; found {
+		var Header2 int
+
+		err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, value, &Header2)
+		if err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error())
+		}
+
+		params.Header2 = &Header2
+
+	}
+
+	return siw.Handler.HeadersExample(c, params)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+	BaseURL     string
+	Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+	RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+	wrapper := ServerInterfaceWrapper{
+		Handler: si,
+	}
+
+	for _, m := range options.Middlewares {
+		router.Use(m)
+	}
+
+	router.Post(options.BaseURL+"/json", wrapper.JSONExample)
+
+	router.Post(options.BaseURL+"/multipart", wrapper.MultipartExample)
+
+	router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+
+	router.Get(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
+
+	router.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
+
+	router.Post(options.BaseURL+"/text", wrapper.TextExample)
+
+	router.Post(options.BaseURL+"/unknown", wrapper.UnknownExample)
+
+	router.Post(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
+
+	router.Post(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
+
+	router.Post(options.BaseURL+"/with-headers", wrapper.HeadersExample)
+
+}
+
+type BadrequestResponse struct {
+}
+
+type ReusableresponseResponseHeaders struct {
+	Header1 string
+	Header2 int
+}
+type ReusableresponseJSONResponse struct {
+	Body Example
+
+	Headers ReusableresponseResponseHeaders
+}
+
+type JSONExampleRequestObject struct {
+	Body *JSONExampleJSONRequestBody
+}
+
+type JSONExampleResponseObject interface {
+	VisitJSONExampleResponse(ctx *fiber.Ctx) error
+}
+
+type JSONExample200JSONResponse Example
+
+func (response JSONExample200JSONResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "application/json")
+	ctx.Status(200)
+
+	return ctx.JSON(&response)
+}
+
+type JSONExample400Response = BadrequestResponse
+
+func (response JSONExample400Response) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type JSONExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response JSONExampledefaultResponse) VisitJSONExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type MultipartExampleRequestObject struct {
+	Body *multipart.Reader
+}
+
+type MultipartExampleResponseObject interface {
+	VisitMultipartExampleResponse(ctx *fiber.Ctx) error
+}
+
+type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+	writer := multipart.NewWriter(ctx.Response().BodyWriter())
+	ctx.Response().Header.Set("Content-Type", writer.FormDataContentType())
+	ctx.Status(200)
+
+	defer writer.Close()
+	return response(writer)
+}
+
+type MultipartExample400Response = BadrequestResponse
+
+func (response MultipartExample400Response) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type MultipartExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type MultipleRequestAndResponseTypesRequestObject struct {
+	JSONBody      *MultipleRequestAndResponseTypesJSONRequestBody
+	FormdataBody  *MultipleRequestAndResponseTypesFormdataRequestBody
+	Body          io.Reader
+	MultipartBody *multipart.Reader
+	TextBody      *MultipleRequestAndResponseTypesTextRequestBody
+}
+
+type MultipleRequestAndResponseTypesResponseObject interface {
+	VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error
+}
+
+type MultipleRequestAndResponseTypes200JSONResponse Example
+
+func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "application/json")
+	ctx.Status(200)
+
+	return ctx.JSON(&response)
+}
+
+type MultipleRequestAndResponseTypes200FormdataResponse Example
+
+func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	ctx.Status(200)
+
+	if form, err := runtime.MarshalForm(response, nil); err != nil {
+		return err
+	} else {
+		_, err := ctx.WriteString(form.Encode())
+		return err
+	}
+}
+
+type MultipleRequestAndResponseTypes200ImagepngResponse struct {
+	Body          io.Reader
+	ContentLength int64
+}
+
+func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "image/png")
+	if response.ContentLength != 0 {
+		ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+	}
+	ctx.Status(200)
+
+	if closer, ok := response.Body.(io.ReadCloser); ok {
+		defer closer.Close()
+	}
+	_, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+	return err
+}
+
+type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	writer := multipart.NewWriter(ctx.Response().BodyWriter())
+	ctx.Response().Header.Set("Content-Type", writer.FormDataContentType())
+	ctx.Status(200)
+
+	defer writer.Close()
+	return response(writer)
+}
+
+type MultipleRequestAndResponseTypes200TextResponse string
+
+func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "text/plain")
+	ctx.Status(200)
+
+	_, err := ctx.WriteString(string(response))
+	return err
+}
+
+type MultipleRequestAndResponseTypes400Response = BadrequestResponse
+
+func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestAndResponseTypesResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type ReservedGoKeywordParametersRequestObject struct {
+	Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+	VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "text/plain")
+	ctx.Status(200)
+
+	_, err := ctx.WriteString(string(response))
+	return err
+}
+
+type ReusableResponsesRequestObject struct {
+	Body *ReusableResponsesJSONRequestBody
+}
+
+type ReusableResponsesResponseObject interface {
+	VisitReusableResponsesResponse(ctx *fiber.Ctx) error
+}
+
+type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
+
+func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1))
+	ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2))
+	ctx.Response().Header.Set("Content-Type", "application/json")
+	ctx.Status(200)
+
+	return ctx.JSON(&response.Body)
+}
+
+type ReusableResponses400Response = BadrequestResponse
+
+func (response ReusableResponses400Response) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type ReusableResponsesdefaultResponse struct {
+	StatusCode int
+}
+
+func (response ReusableResponsesdefaultResponse) VisitReusableResponsesResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type TextExampleRequestObject struct {
+	Body *TextExampleTextRequestBody
+}
+
+type TextExampleResponseObject interface {
+	VisitTextExampleResponse(ctx *fiber.Ctx) error
+}
+
+type TextExample200TextResponse string
+
+func (response TextExample200TextResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "text/plain")
+	ctx.Status(200)
+
+	_, err := ctx.WriteString(string(response))
+	return err
+}
+
+type TextExample400Response = BadrequestResponse
+
+func (response TextExample400Response) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type TextExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response TextExampledefaultResponse) VisitTextExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type UnknownExampleRequestObject struct {
+	Body io.Reader
+}
+
+type UnknownExampleResponseObject interface {
+	VisitUnknownExampleResponse(ctx *fiber.Ctx) error
+}
+
+type UnknownExample200Videomp4Response struct {
+	Body          io.Reader
+	ContentLength int64
+}
+
+func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "video/mp4")
+	if response.ContentLength != 0 {
+		ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+	}
+	ctx.Status(200)
+
+	if closer, ok := response.Body.(io.ReadCloser); ok {
+		defer closer.Close()
+	}
+	_, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+	return err
+}
+
+type UnknownExample400Response = BadrequestResponse
+
+func (response UnknownExample400Response) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type UnknownExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response UnknownExampledefaultResponse) VisitUnknownExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type UnspecifiedContentTypeRequestObject struct {
+	ContentType string
+	Body        io.Reader
+}
+
+type UnspecifiedContentTypeResponseObject interface {
+	VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error
+}
+
+type UnspecifiedContentType200VideoResponse struct {
+	Body          io.Reader
+	ContentType   string
+	ContentLength int64
+}
+
+func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", response.ContentType)
+	if response.ContentLength != 0 {
+		ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
+	}
+	ctx.Status(200)
+
+	if closer, ok := response.Body.(io.ReadCloser); ok {
+		defer closer.Close()
+	}
+	_, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+	return err
+}
+
+type UnspecifiedContentType400Response = BadrequestResponse
+
+func (response UnspecifiedContentType400Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type UnspecifiedContentType401Response struct {
+}
+
+func (response UnspecifiedContentType401Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+	ctx.Status(401)
+	return nil
+}
+
+type UnspecifiedContentType403Response struct {
+}
+
+func (response UnspecifiedContentType403Response) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+	ctx.Status(403)
+	return nil
+}
+
+type UnspecifiedContentTypedefaultResponse struct {
+	StatusCode int
+}
+
+func (response UnspecifiedContentTypedefaultResponse) VisitUnspecifiedContentTypeResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type URLEncodedExampleRequestObject struct {
+	Body *URLEncodedExampleFormdataRequestBody
+}
+
+type URLEncodedExampleResponseObject interface {
+	VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error
+}
+
+type URLEncodedExample200FormdataResponse Example
+
+func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	ctx.Status(200)
+
+	if form, err := runtime.MarshalForm(response, nil); err != nil {
+		return err
+	} else {
+		_, err := ctx.WriteString(form.Encode())
+		return err
+	}
+}
+
+type URLEncodedExample400Response = BadrequestResponse
+
+func (response URLEncodedExample400Response) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type URLEncodedExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response URLEncodedExampledefaultResponse) VisitURLEncodedExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+type HeadersExampleRequestObject struct {
+	Params HeadersExampleParams
+	Body   *HeadersExampleJSONRequestBody
+}
+
+type HeadersExampleResponseObject interface {
+	VisitHeadersExampleResponse(ctx *fiber.Ctx) error
+}
+
+type HeadersExample200ResponseHeaders struct {
+	Header1 string
+	Header2 int
+}
+
+type HeadersExample200JSONResponse struct {
+	Body    Example
+	Headers HeadersExample200ResponseHeaders
+}
+
+func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1))
+	ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2))
+	ctx.Response().Header.Set("Content-Type", "application/json")
+	ctx.Status(200)
+
+	return ctx.JSON(&response.Body)
+}
+
+type HeadersExample400Response = BadrequestResponse
+
+func (response HeadersExample400Response) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(400)
+	return nil
+}
+
+type HeadersExampledefaultResponse struct {
+	StatusCode int
+}
+
+func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
+	ctx.Status(response.StatusCode)
+	return nil
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+	// (POST /json)
+	JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error)
+
+	// (POST /multipart)
+	MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+
+	// (POST /multiple)
+	MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+
+	// (GET /reserved-go-keyword-parameters/{type})
+	ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
+	// (POST /reusable-responses)
+	ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
+
+	// (POST /text)
+	TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error)
+
+	// (POST /unknown)
+	UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error)
+
+	// (POST /unspecified-content-type)
+	UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error)
+
+	// (POST /urlencoded)
+	URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error)
+
+	// (POST /with-headers)
+	HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
+
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+	return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+	ssi         StrictServerInterface
+	middlewares []StrictMiddlewareFunc
+}
+
+// JSONExample operation middleware
+func (sh *strictHandler) JSONExample(ctx *fiber.Ctx) error {
+	var request JSONExampleRequestObject
+
+	var body JSONExampleJSONRequestBody
+	if err := ctx.BodyParser(&body); err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	}
+	request.Body = &body
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.JSONExample(ctx.UserContext(), request.(JSONExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "JSONExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(JSONExampleResponseObject); ok {
+		if err := validResponse.VisitJSONExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// MultipartExample operation middleware
+func (sh *strictHandler) MultipartExample(ctx *fiber.Ctx) error {
+	var request MultipartExampleRequestObject
+
+	request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.MultipartExample(ctx.UserContext(), request.(MultipartExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "MultipartExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(MultipartExampleResponseObject); ok {
+		if err := validResponse.VisitMultipartExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
+	var request MultipleRequestAndResponseTypesRequestObject
+
+	if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/json") {
+		var body MultipleRequestAndResponseTypesJSONRequestBody
+		if err := ctx.BodyParser(&body); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+		request.JSONBody = &body
+	}
+	if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/x-www-form-urlencoded") {
+		var body MultipleRequestAndResponseTypesFormdataRequestBody
+		if err := ctx.BodyParser(&body); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+		request.FormdataBody = &body
+	}
+	if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "image/png") {
+		request.Body = bytes.NewReader(ctx.Request().Body())
+	}
+	if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "multipart/form-data") {
+		request.MultipartBody = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+	}
+	if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "text/plain") {
+		data := ctx.Request().Body()
+		body := MultipleRequestAndResponseTypesTextRequestBody(data)
+		request.TextBody = &body
+	}
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.MultipleRequestAndResponseTypes(ctx.UserContext(), request.(MultipleRequestAndResponseTypesRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "MultipleRequestAndResponseTypes")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok {
+		if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(ctx *fiber.Ctx, pType string) error {
+	var request ReservedGoKeywordParametersRequestObject
+
+	request.Type = pType
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.ReservedGoKeywordParameters(ctx.UserContext(), request.(ReservedGoKeywordParametersRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "ReservedGoKeywordParameters")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+		if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// ReusableResponses operation middleware
+func (sh *strictHandler) ReusableResponses(ctx *fiber.Ctx) error {
+	var request ReusableResponsesRequestObject
+
+	var body ReusableResponsesJSONRequestBody
+	if err := ctx.BodyParser(&body); err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	}
+	request.Body = &body
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.ReusableResponses(ctx.UserContext(), request.(ReusableResponsesRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "ReusableResponses")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(ReusableResponsesResponseObject); ok {
+		if err := validResponse.VisitReusableResponsesResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// TextExample operation middleware
+func (sh *strictHandler) TextExample(ctx *fiber.Ctx) error {
+	var request TextExampleRequestObject
+
+	data := ctx.Request().Body()
+	body := TextExampleTextRequestBody(data)
+	request.Body = &body
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.TextExample(ctx.UserContext(), request.(TextExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "TextExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(TextExampleResponseObject); ok {
+		if err := validResponse.VisitTextExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// UnknownExample operation middleware
+func (sh *strictHandler) UnknownExample(ctx *fiber.Ctx) error {
+	var request UnknownExampleRequestObject
+
+	request.Body = bytes.NewReader(ctx.Request().Body())
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.UnknownExample(ctx.UserContext(), request.(UnknownExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "UnknownExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(UnknownExampleResponseObject); ok {
+		if err := validResponse.VisitUnknownExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// UnspecifiedContentType operation middleware
+func (sh *strictHandler) UnspecifiedContentType(ctx *fiber.Ctx) error {
+	var request UnspecifiedContentTypeRequestObject
+
+	request.ContentType = string(ctx.Request().Header.ContentType())
+
+	request.Body = bytes.NewReader(ctx.Request().Body())
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.UnspecifiedContentType(ctx.UserContext(), request.(UnspecifiedContentTypeRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "UnspecifiedContentType")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok {
+		if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// URLEncodedExample operation middleware
+func (sh *strictHandler) URLEncodedExample(ctx *fiber.Ctx) error {
+	var request URLEncodedExampleRequestObject
+
+	var body URLEncodedExampleFormdataRequestBody
+	if err := ctx.BodyParser(&body); err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	}
+	request.Body = &body
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.URLEncodedExample(ctx.UserContext(), request.(URLEncodedExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "URLEncodedExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok {
+		if err := validResponse.VisitURLEncodedExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// HeadersExample operation middleware
+func (sh *strictHandler) HeadersExample(ctx *fiber.Ctx, params HeadersExampleParams) error {
+	var request HeadersExampleRequestObject
+
+	request.Params = params
+
+	var body HeadersExampleJSONRequestBody
+	if err := ctx.BodyParser(&body); err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	}
+	request.Body = &body
+
+	handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+		return sh.ssi.HeadersExample(ctx.UserContext(), request.(HeadersExampleRequestObject))
+	}
+	for _, middleware := range sh.middlewares {
+		handler = middleware(handler, "HeadersExample")
+	}
+
+	response, err := handler(ctx, request)
+
+	if err != nil {
+		return fiber.NewError(fiber.StatusBadRequest, err.Error())
+	} else if validResponse, ok := response.(HeadersExampleResponseObject); ok {
+		if err := validResponse.VisitHeadersExampleResponse(ctx); err != nil {
+			return fiber.NewError(fiber.StatusBadRequest, err.Error())
+		}
+	} else if response != nil {
+		return fmt.Errorf("Unexpected response type: %T", response)
+	}
+	return nil
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+	"H4sIAAAAAAAC/+xYX2/bNhD/KgS3p0KynDRPeluDotu6rYOTPg15oMWzzFYiuePJimHouw8UJf+pFS/O",
+	"7BgY+mbRd787/u4Pj1zxzJTWaNDkeLriCM4a7aD9mAqJ8HcFjvyXBJehsqSM5il/J+Sk+6+JOELlxLSA",
+	"Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
+	"DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
+	"eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
+	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
+	"33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
+	"0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
+	"3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
+	"FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
+	"QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
+	"Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
+	"fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
+	"5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
+	"MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
+	"qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
+	"AP//O0NNuucUAAA=",
+}
+
+// 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/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go
new file mode 100644
index 0000000..b0724db
--- /dev/null
+++ b/internal/test/strict-server/fiber/server.go
@@ -0,0 +1,106 @@
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+
+package api
+
+import (
+	"context"
+	"io"
+	"mime/multipart"
+)
+
+type StrictServer struct {
+}
+
+func (s StrictServer) JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error) {
+	return JSONExample200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error) {
+	return MultipartExample200MultipartResponse(func(writer *multipart.Writer) error {
+		for {
+			part, err := request.Body.NextPart()
+			if err == io.EOF {
+				return nil
+			} else if err != nil {
+				return err
+			}
+			w, err := writer.CreatePart(part.Header)
+			if err != nil {
+				return err
+			}
+			_, err = io.Copy(w, part)
+			if err != nil {
+				return err
+			}
+			if err = part.Close(); err != nil {
+				return err
+			}
+		}
+	}), nil
+}
+
+func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
+	switch {
+	case request.Body != nil:
+		return MultipleRequestAndResponseTypes200ImagepngResponse{Body: request.Body}, nil
+	case request.JSONBody != nil:
+		return MultipleRequestAndResponseTypes200JSONResponse(*request.JSONBody), nil
+	case request.FormdataBody != nil:
+		return MultipleRequestAndResponseTypes200FormdataResponse(*request.FormdataBody), nil
+	case request.TextBody != nil:
+		return MultipleRequestAndResponseTypes200TextResponse(*request.TextBody), nil
+	case request.MultipartBody != nil:
+		return MultipleRequestAndResponseTypes200MultipartResponse(func(writer *multipart.Writer) error {
+			for {
+				part, err := request.MultipartBody.NextPart()
+				if err == io.EOF {
+					return nil
+				} else if err != nil {
+					return err
+				}
+				w, err := writer.CreatePart(part.Header)
+				if err != nil {
+					return err
+				}
+				_, err = io.Copy(w, part)
+				if err != nil {
+					return err
+				}
+				if err = part.Close(); err != nil {
+					return err
+				}
+			}
+		}), nil
+	default:
+		return MultipleRequestAndResponseTypes400Response{}, nil
+	}
+}
+
+func (s StrictServer) TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error) {
+	return TextExample200TextResponse(*request.Body), nil
+}
+
+func (s StrictServer) UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error) {
+	return UnknownExample200Videomp4Response{Body: request.Body}, nil
+}
+
+func (s StrictServer) UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error) {
+	return UnspecifiedContentType200VideoResponse{Body: request.Body, ContentType: request.ContentType}, nil
+}
+
+func (s StrictServer) URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error) {
+	return URLEncodedExample200FormdataResponse(*request.Body), nil
+}
+
+func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) {
+	return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
+}
+
+func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
+	return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
+}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+	return ReservedGoKeywordParameters200TextResponse(""), nil
+}
diff --git a/internal/test/strict-server/fiber/types.cfg.yaml b/internal/test/strict-server/fiber/types.cfg.yaml
new file mode 100644
index 0000000..4ea1d8a
--- /dev/null
+++ b/internal/test/strict-server/fiber/types.cfg.yaml
@@ -0,0 +1,4 @@
+package: api
+generate:
+  models: true
+output: types.gen.go
diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go
new file mode 100644
index 0000000..33827cb
--- /dev/null
+++ b/internal/test/strict-server/fiber/types.gen.go
@@ -0,0 +1,54 @@
+// 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
+
+// Example defines model for example.
+type Example struct {
+	Value *string `json:"value,omitempty"`
+}
+
+// Reusableresponse defines model for reusableresponse.
+type Reusableresponse = Example
+
+// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
+type MultipleRequestAndResponseTypesTextBody = string
+
+// TextExampleTextBody defines parameters for TextExample.
+type TextExampleTextBody = string
+
+// HeadersExampleParams defines parameters for HeadersExample.
+type HeadersExampleParams struct {
+	Header1 string `json:"header1"`
+	Header2 *int   `json:"header2,omitempty"`
+}
+
+// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
+type JSONExampleJSONRequestBody = Example
+
+// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
+type MultipartExampleMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
+type MultipleRequestAndResponseTypesJSONRequestBody = Example
+
+// MultipleRequestAndResponseTypesFormdataRequestBody defines body for MultipleRequestAndResponseTypes for application/x-www-form-urlencoded ContentType.
+type MultipleRequestAndResponseTypesFormdataRequestBody = Example
+
+// MultipleRequestAndResponseTypesMultipartRequestBody defines body for MultipleRequestAndResponseTypes for multipart/form-data ContentType.
+type MultipleRequestAndResponseTypesMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
+type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+
+// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
+type ReusableResponsesJSONRequestBody = Example
+
+// TextExampleTextRequestBody defines body for TextExample for text/plain ContentType.
+type TextExampleTextRequestBody = TextExampleTextBody
+
+// URLEncodedExampleFormdataRequestBody defines body for URLEncodedExample for application/x-www-form-urlencoded ContentType.
+type URLEncodedExampleFormdataRequestBody = Example
+
+// HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType.
+type HeadersExampleJSONRequestBody = Example
diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go
index dd9839c..d3d9561 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -1135,18 +1135,18 @@ var swaggerSpec = []string{
 	"Xt3LZ0YT6FZVWFuoTHjV5Ivz+ivusjmUwv/6EWHGU/5DsnElCf+6BB5FaQvgTdNE33jw6SOP+ByEBGy9",
 	"DT+vdrFpaYGn3BEqnXMPEsSuB8WUJsgBvTUv2jnhBXo/0hW3aCwgqcDRQhQVDFvqVsz0C2QUdqD0zOxz",
 	"eWs0CaUdk2o2AwRNrCOPeQzHXGWtQQLJpkvmLWTEHOACkEecFHnH+N32OuscdjziC0AXDF2NxqOxj5ex",
-	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uSgKkExpMt7HKiM34q0pbCP/i+zU",
-	"33dc+rRpM+idkctzZEybmFv5fD0ev1JiNhG/CcaGMNZOJVsV1sLMRFUMkP5Zf9Wm1gwQDXY7S8qqIGUF",
-	"0nawdtn+vRd5DuVrvGRmsIylIHEm1k9l6aLEd81gsEju5qZ2bG5qRoZJEAWrFc1Zr/hNdSvNBHNK5wWw",
-	"3qloMJIFdD33Jy0n3V7uPcbZaynaQXmM67qO2+BVWIDOjAT5MlhVihwSq/NddY8tiKd8uiSftvvd9URJ",
-	"FHGCR0psIZQ+fHS8Ujv5zvTJCjuUK0J7JMo4N/FXWNYGZWwFihII0CUrb73xwDkMlPKfa0mWCc2mwLQo",
-	"QTIxI0D2wbAO0u2V7KSz+8F8DCIbqPa8XX+kf624p6Q9g3nEvQGeBlZCXSv0QSesIDpA28O/5ud/CkDP",
-	"Zpj04h1Tw22wb1Fr6hBmzrfEocgN8BcsTbYkLjMwHM64vdn3Nc4gH8mnz/17eHzWkX/C1vfatX0sYVVY",
-	"fJqzTus5tL2wkz6DxYWSYJLS3hyJfDFSnYVMzRTIuNtFHHx7qiXcGp0h0O4I5O8T2hBbg/lrDs2BBQYi",
-	"5gyrgZWVI2aFc0xR20UKFa5KEvaax+eNZ7fB0v2mnR6K6pszxfTNpSJ6M746XuXtmfNmZ5R5oh4nv70P",
-	"MsfeF082Mx058Z3O7oXK2V9S4q0XleES/jkIbM70DNTCT0RaMgSqUINkCyX6R4C92uwANmEdmoWCG5tp",
-	"qH/dOWYgig5iXfPo0AvQw//4eeKc72bnztMm4uGJKyRLhYWPKJFNkyQ8jY1cLfIccKRMIqzizUPzTwAA",
-	"AP//O0NNuucUAAA=",
+	"oIVVPOVv26WIW0HzdkPrAFkzFPdf7z79wZRjoiJTClKZKIolKwW6uShAMqXJeBerjNyIt5awDfwvstN+",
+	"31Hps6ZNoHdGLs+RMG1ebqXz9Xj8SnnZRPwmGBvCWDuVbBVYCzMTVTHA+Wf9VZtaM0A02O0sKauClBVI",
+	"27HaZfv3XuQ5lK/xkpnBMpaCxJlYP5WlixLf9YLBGrmbm9qxuakZGSZBFKxWNGe94jfFrTQTzCmdF8B6",
+	"p6LBSBbQtdyftJx0e7n3GGevpWgH5TGu6zpug1dhATozEuTLYFUpckisznfVPbYgnvLpknza7jfXEyVR",
+	"xAkeKbGFUPrwyfFK7eQ70ycr7FCuCO2JKOPcxF9hWRuUsRUoSiBAl6y89cYD5zBQyn+uJVkmNJsC06IE",
+	"ycSMANkHwzpIt1eyk87uB/MxiGyg2uN2/ZH+teKekvYI5hH3BngaWAl1rdAHnbCC6ABtD/+an/8pAD2b",
+	"YdCLd0wNt8G+Ra2pQ5g53xKHIjfAX7A02ZK4zMBwOOP2Rt/XOIN8JJ8+9+/h8VlH/glb32vX9rGEVWHx",
+	"ac46refQ9sJO+gwWF0qCSUp7cyTyxUh1FjI1UyDjbhdx8O2plnBrdIZAuyOQv05oQ2wN5m85NAcWGIiY",
+	"M6wGVlaOmBXOMUVtFylUuClJ2Gsenzee3QZL95t2eiiqb84U0zeXiujN+Op4lbdnzpudUeaJepz89j7I",
+	"HHtfPNnMdOTEdzq7Fypnf0mJtx5Uhkv45yCwOdMzUAs/EWnJEKhCDZItlOgfAfZqswPYhHVoFgpubKah",
+	"/nHnmIEoOoh1zaNDD0AP/+PniXM+m507T5uIhxeukCwVFj6iRDZNkvAyNnK1yHPAkTKJsIo3D80/AQAA",
+	"///iKNcc5hQAAA==",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml
index da0ed07..a9906f6 100644
--- a/internal/test/strict-server/strict-schema.yaml
+++ b/internal/test/strict-server/strict-schema.yaml
@@ -9,7 +9,7 @@ paths:
   /json:
     post:
       operationId: JSONExample
-      description: JSON is automatically marshalled into structs.
+      description: JSON is automatically marshaled into structs.
       requestBody:
         content:
           application/json:
diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go
index 860cc4c..bfbb9bc 100644
--- a/internal/test/strict-server/strict_test.go
+++ b/internal/test/strict-server/strict_test.go
@@ -13,57 +13,68 @@ import (
 
 	"github.com/gin-gonic/gin"
 	"github.com/go-chi/chi/v5"
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/fiber/v2/middleware/adaptor"
 	"github.com/labstack/echo/v4"
 	"github.com/stretchr/testify/assert"
 
-	"github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
-	api3 "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
-	api4 "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
-	api2 "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
+	chiAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
+	clientAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
+	echoAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
+	fiberAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/fiber"
+	ginAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
 	"github.com/deepmap/oapi-codegen/pkg/runtime"
 	"github.com/deepmap/oapi-codegen/pkg/testutil"
 )
 
 func TestChiServer(t *testing.T) {
-	server := api.StrictServer{}
-	strictHandler := api.NewStrictHandler(server, nil)
+	server := chiAPI.StrictServer{}
+	strictHandler := chiAPI.NewStrictHandler(server, nil)
 	r := chi.NewRouter()
-	handler := api.HandlerFromMux(strictHandler, r)
+	handler := chiAPI.HandlerFromMux(strictHandler, r)
 	testImpl(t, handler)
 }
 
 func TestEchoServer(t *testing.T) {
-	server := api4.StrictServer{}
-	strictHandler := api4.NewStrictHandler(server, nil)
+	server := echoAPI.StrictServer{}
+	strictHandler := echoAPI.NewStrictHandler(server, nil)
 	e := echo.New()
-	api4.RegisterHandlers(e, strictHandler)
+	echoAPI.RegisterHandlers(e, strictHandler)
 	testImpl(t, e)
 }
 
 func TestGinServer(t *testing.T) {
-	server := api2.StrictServer{}
-	strictHandler := api2.NewStrictHandler(server, nil)
+	server := ginAPI.StrictServer{}
+	strictHandler := ginAPI.NewStrictHandler(server, nil)
 	gin.SetMode(gin.ReleaseMode)
 	r := gin.New()
-	api2.RegisterHandlers(r, strictHandler)
+	ginAPI.RegisterHandlers(r, strictHandler)
 	testImpl(t, r)
 }
 
+func TestFiberServer(t *testing.T) {
+	server := fiberAPI.StrictServer{}
+	strictHandler := fiberAPI.NewStrictHandler(server, nil)
+	r := fiber.New()
+	fiberAPI.RegisterHandlers(r, strictHandler)
+	testImpl(t, adaptor.FiberApp(r))
+}
+
 func testImpl(t *testing.T, handler http.Handler) {
 	t.Run("JSONExample", func(t *testing.T) {
 		value := "123"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		rr := testutil.NewRequest().Post("/json").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
 		assert.Equal(t, http.StatusOK, rr.Code)
 		assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err := json.NewDecoder(rr.Body).Decode(&responseBody)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
 	})
 	t.Run("URLEncodedExample", func(t *testing.T) {
 		value := "456"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
 		assert.NoError(t, err)
 		rr := testutil.NewRequest().Post("/urlencoded").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
@@ -71,7 +82,7 @@ func testImpl(t *testing.T, handler http.Handler) {
 		assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
 		values, err := url.ParseQuery(rr.Body.String())
 		assert.NoError(t, err)
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err = runtime.BindForm(&responseBody, values, nil, nil)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
@@ -116,18 +127,18 @@ func testImpl(t *testing.T, handler http.Handler) {
 	})
 	t.Run("MultipleRequestAndResponseTypesJSON", func(t *testing.T) {
 		value := "123"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		rr := testutil.NewRequest().Post("/multiple").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
 		assert.Equal(t, http.StatusOK, rr.Code)
 		assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err := json.NewDecoder(rr.Body).Decode(&responseBody)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
 	})
 	t.Run("MultipleRequestAndResponseTypesFormdata", func(t *testing.T) {
 		value := "456"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
 		assert.NoError(t, err)
 		rr := testutil.NewRequest().Post("/multiple").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
@@ -135,7 +146,7 @@ func testImpl(t *testing.T, handler http.Handler) {
 		assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
 		values, err := url.ParseQuery(rr.Body.String())
 		assert.NoError(t, err)
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err = runtime.BindForm(&responseBody, values, nil, nil)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
@@ -182,11 +193,11 @@ func testImpl(t *testing.T, handler http.Handler) {
 		header1 := "value1"
 		header2 := "890"
 		value := "asdf"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		rr := testutil.NewRequest().Post("/with-headers").WithHeader("header1", header1).WithHeader("header2", header2).WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
 		assert.Equal(t, http.StatusOK, rr.Code)
 		assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err := json.NewDecoder(rr.Body).Decode(&responseBody)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
@@ -203,11 +214,11 @@ func testImpl(t *testing.T, handler http.Handler) {
 	})
 	t.Run("ReusableResponses", func(t *testing.T) {
 		value := "jkl;"
-		requestBody := api3.Example{Value: &value}
+		requestBody := clientAPI.Example{Value: &value}
 		rr := testutil.NewRequest().Post("/reusable-responses").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
 		assert.Equal(t, http.StatusOK, rr.Code)
 		assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
-		var responseBody api3.Example
+		var responseBody clientAPI.Example
 		err := json.NewDecoder(rr.Body).Decode(&responseBody)
 		assert.NoError(t, err)
 		assert.Equal(t, requestBody, responseBody)
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index 0da9dfb..6776526 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -280,6 +280,23 @@ func TestSwaggerUriToGorillaUri(t *testing.T) { // TODO
 	assert.Equal(t, "/path/{arg}/foo", SwaggerUriToGorillaUri("/path/{?arg*}/foo"))
 }
 
+func TestSwaggerUriToFiberUri(t *testing.T) {
+	assert.Equal(t, "/path", SwaggerUriToFiberUri("/path"))
+	assert.Equal(t, "/path/:arg", SwaggerUriToFiberUri("/path/{arg}"))
+	assert.Equal(t, "/path/:arg1/:arg2", SwaggerUriToFiberUri("/path/{arg1}/{arg2}"))
+	assert.Equal(t, "/path/:arg1/:arg2/foo", SwaggerUriToFiberUri("/path/{arg1}/{arg2}/foo"))
+
+	// Make sure all the exploded and alternate formats match too
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{arg*}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{.arg*}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{;arg*}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg}/foo"))
+	assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg*}/foo"))
+}
+
 func TestOrderedParamsFromUri(t *testing.T) {
 	result := OrderedParamsFromUri("/path/{param1}/{.param2}/{;param3*}/foo")
 	assert.EqualValues(t, []string{"param1", "param2", "param3"}, result)
diff --git a/pkg/fiber-middleware/oapi_validate_test.go b/pkg/fiber-middleware/oapi_validate_test.go
new file mode 100644
index 0000000..9201e13
--- /dev/null
+++ b/pkg/fiber-middleware/oapi_validate_test.go
@@ -0,0 +1,434 @@
+package middleware
+
+import (
+	"bytes"
+	"context"
+	_ "embed"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"testing"
+
+	"github.com/getkin/kin-openapi/openapi3"
+	"github.com/getkin/kin-openapi/openapi3filter"
+	"github.com/gofiber/fiber/v2"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+//go:embed test_spec.yaml
+var testSchema []byte
+
+func doGet(t *testing.T, app *fiber.App, rawURL string) *http.Response {
+	t.Helper()
+
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("invalid URL %q: %v", rawURL, err)
+	}
+
+	req := httptest.NewRequest("GET", u.RequestURI(), nil)
+	req.Header.Add("Accept", "application/json")
+	req.Host = u.Host
+
+	r, err := app.Test(req)
+	if err != nil {
+		t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
+	}
+
+	return r
+}
+
+func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) *http.Response {
+	t.Helper()
+
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("invalid url %q: %v", rawURL, err)
+	}
+
+	buf, err := json.Marshal(jsonBody)
+	if err != nil {
+		t.Fatalf("failed to marshal: %v", err)
+	}
+
+	req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
+	req.Header.Add("Accept", "application/json")
+	req.Header.Add("Content-Type", "application/json")
+	req.Host = u.Host
+
+	r, err := app.Test(req)
+	if err != nil {
+		t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
+	}
+
+	return r
+}
+
+func TestOapiRequestValidator(t *testing.T) {
+
+	swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+	require.NoError(t, err, "Error initializing swagger")
+
+	// Create a new fiber router
+	app := fiber.New()
+
+	// Set up an authenticator to check authenticated function. It will allow
+	// access to "someScope", but disallow others.
+	options := Options{
+		ErrorHandler: func(c *fiber.Ctx, message string, statusCode int) {
+			_ = c.Status(statusCode).SendString("test: " + message)
+		},
+		Options: openapi3filter.Options{
+			AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
+				// The fiber context should be propagated into here.
+				gCtx := GetFiberContext(c)
+				assert.NotNil(t, gCtx)
+				// As should user data
+				assert.EqualValues(t, "hi!", GetUserData(c))
+
+				for _, s := range input.Scopes {
+					if s == "someScope" {
+						return nil
+					}
+					if s == "unauthorized" {
+						return errors.New("unauthorized")
+					}
+				}
+				return errors.New("forbidden")
+			},
+		},
+		UserData: "hi!",
+	}
+
+	// Install our OpenApi based request validator
+	app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+	called := false
+
+	// Install a request handler for /resource. We want to make sure it doesn't
+	// get called.
+	app.Get("/resource", func(c *fiber.Ctx) error {
+		called = true
+		return nil
+	})
+	// Let's send the request to the wrong server, this should fail validation
+	{
+		res := doGet(t, app, "https://not.deepmap.ai/resource")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		assert.False(t, called, "Handler should not have been called")
+	}
+
+	// Let's send a good request, it should pass
+	{
+		res := doGet(t, app, "https://deepmap.ai/resource")
+		assert.Equal(t, http.StatusOK, res.StatusCode)
+		assert.True(t, called, "Handler should have been called")
+		called = false
+	}
+
+	// Send an out-of-spec parameter
+	{
+		res := doGet(t, app, "https://deepmap.ai/resource?id=500")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Send a bad parameter type
+	{
+		res := doGet(t, app, "https://deepmap.ai/resource?id=foo")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Add a handler for the POST message
+	app.Post("/resource", func(c *fiber.Ctx) error {
+		called = true
+		return c.SendStatus(http.StatusNoContent)
+	})
+
+	called = false
+	// Send a good request body
+	{
+		body := struct {
+			Name string `json:"name"`
+		}{
+			Name: "Marcin",
+		}
+		res := doPost(t, app, "https://deepmap.ai/resource", body)
+		assert.Equal(t, http.StatusNoContent, res.StatusCode)
+		assert.True(t, called, "Handler should have been called")
+		called = false
+	}
+
+	// Send a malformed body
+	{
+		body := struct {
+			Name int `json:"name"`
+		}{
+			Name: 7,
+		}
+		res := doPost(t, app, "https://deepmap.ai/resource", body)
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	app.Get("/protected_resource", func(c *fiber.Ctx) error {
+		called = true
+		return c.SendStatus(http.StatusNoContent)
+	})
+
+	// Call a protected function to which we have access
+	{
+		res := doGet(t, app, "https://deepmap.ai/protected_resource")
+		assert.Equal(t, http.StatusNoContent, res.StatusCode)
+		assert.True(t, called, "Handler should have been called")
+		called = false
+	}
+
+	app.Get("/protected_resource2", func(c *fiber.Ctx) error {
+		called = true
+		return c.SendStatus(http.StatusNoContent)
+	})
+	// Call a protected function to which we don't have access
+	{
+		res := doGet(t, app, "https://deepmap.ai/protected_resource2")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	app.Get("/protected_resource_401", func(c *fiber.Ctx) error {
+		called = true
+		return c.SendStatus(http.StatusNoContent)
+	})
+	// Call a protected function without credentials
+	{
+		res := doGet(t, app, "https://deepmap.ai/protected_resource_401")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", string(body))
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+}
+
+func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
+	swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+	require.NoError(t, err, "Error initializing swagger")
+
+	app := fiber.New()
+
+	// Set up an authenticator to check authenticated function. It will allow
+	// access to "someScope", but disallow others.
+	options := Options{
+		Options: openapi3filter.Options{
+			ExcludeRequestBody:    false,
+			ExcludeResponseBody:   false,
+			IncludeResponseStatus: true,
+			MultiError:            true,
+		},
+	}
+
+	// register middleware
+	app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+	called := false
+
+	// Install a request handler for /resource. We want to make sure it doesn't
+	// get called.
+	app.Get("/multiparamresource", func(c *fiber.Ctx) error {
+		called = true
+		return nil
+	})
+
+	// Let's send a good request, it should pass
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
+		assert.Equal(t, http.StatusOK, res.StatusCode)
+		assert.True(t, called, "Handler should have been called")
+		called = false
+	}
+
+	// Let's send a request with a missing parameter, it should return
+	// a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "multiple errors encountered")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a 2 missing parameters, it should return
+	// a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "multiple errors encountered")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "value is required but missing")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a 1 missing parameter, and another outside
+	// or the parameters. It should return a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "multiple errors encountered")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "number must be at most 100")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a parameters that do not meet spec. It should
+	// return a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "multiple errors encountered")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "number must be at least 10")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+}
+
+func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
+	swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
+	require.NoError(t, err, "Error initializing swagger")
+
+	app := fiber.New()
+
+	// Set up an authenticator to check authenticated function. It will allow
+	// access to "someScope", but disallow others.
+	options := Options{
+		Options: openapi3filter.Options{
+			ExcludeRequestBody:    false,
+			ExcludeResponseBody:   false,
+			IncludeResponseStatus: true,
+			MultiError:            true,
+		},
+		MultiErrorHandler: func(me openapi3.MultiError) error {
+			return fmt.Errorf("Bad stuff -  %s", me.Error())
+		},
+	}
+
+	// register middleware
+	app.Use(OapiRequestValidatorWithOptions(swagger, &options))
+
+	called := false
+
+	// Install a request handler for /resource. We want to make sure it doesn't
+	// get called.
+	app.Get("/multiparamresource", func(c *fiber.Ctx) error {
+		called = true
+		return nil
+	})
+
+	// Let's send a good request, it should pass
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
+		assert.Equal(t, http.StatusOK, res.StatusCode)
+		assert.True(t, called, "Handler should have been called")
+		called = false
+	}
+
+	// Let's send a request with a missing parameter, it should return
+	// a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "Bad stuff")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a 2 missing parameters, it should return
+	// a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "Bad stuff")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "value is required but missing")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a 1 missing parameter, and another outside
+	// or the parameters. It should return a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "Bad stuff")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "number must be at most 100")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "value is required but missing")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+
+	// Let's send a request with a parameters that do not meet spec. It should
+	// return a bad status
+	{
+		res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
+		assert.Equal(t, http.StatusBadRequest, res.StatusCode)
+		body, err := io.ReadAll(res.Body)
+		if assert.NoError(t, err) {
+			assert.Contains(t, string(body), "Bad stuff")
+			assert.Contains(t, string(body), "parameter \"id\"")
+			assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
+			assert.Contains(t, string(body), "parameter \"id2\"")
+			assert.Contains(t, string(body), "number must be at least 10")
+		}
+		assert.False(t, called, "Handler should not have been called")
+		called = false
+	}
+}
diff --git a/pkg/fiber-middleware/test_spec.yaml b/pkg/fiber-middleware/test_spec.yaml
new file mode 100644
index 0000000..6e0a241
--- /dev/null
+++ b/pkg/fiber-middleware/test_spec.yaml
@@ -0,0 +1,103 @@
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: TestServer
+servers:
+  - url: http://deepmap.ai/
+paths:
+  /resource:
+    get:
+      operationId: getResource
+      parameters:
+        - name: id
+          in: query
+          schema:
+            type: integer
+            minimum: 10
+            maximum: 100
+      responses:
+        '200':
+          description: success
+          content:
+            application/json:
+              schema:
+                properties:
+                  name:
+                    type: string
+                  id:
+                    type: integer
+    post:
+      operationId: createResource
+      responses:
+        '204':
+          description: No content
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              properties:
+                name:
+                  type: string
+  /protected_resource:
+    get:
+      operationId: getProtectedResource
+      security:
+        - BearerAuth:
+            - someScope
+      responses:
+        '204':
+          description: no content
+  /protected_resource2:
+    get:
+      operationId: getProtectedResource
+      security:
+        - BearerAuth:
+            - otherScope
+      responses:
+        '204':
+          description: no content
+  /protected_resource_401:
+    get:
+      operationId: getProtectedResource
+      security:
+        - BearerAuth:
+            - unauthorized
+      responses:
+        '401':
+          description: no content
+  /multiparamresource:
+    get:
+      operationId: getResource
+      parameters:
+        - name: id
+          in: query
+          required: true
+          schema:
+            type: integer
+            minimum: 10
+            maximum: 100
+        - name: id2
+          required: true
+          in: query
+          schema:
+            type: integer
+            minimum: 10
+            maximum: 100
+      responses:
+        '200':
+          description: success
+          content:
+            application/json:
+              schema:
+                properties:
+                  name:
+                    type: string
+                  id:
+                    type: integer
+components:
+  securitySchemes:
+    BearerAuth:
+      type: http
+      scheme: bearer
+      bearerFormat: JWT
diff --git a/pkg/runtime/bindform_test.go b/pkg/runtime/bindform_test.go
index 159cef2..398f9b0 100644
--- a/pkg/runtime/bindform_test.go
+++ b/pkg/runtime/bindform_test.go
@@ -159,9 +159,9 @@ func TestMarshalForm(t *testing.T) {
 	}
 
 	for k, v := range testCases {
-		marshalled, err := MarshalForm(v, nil)
+		marshaled, err := MarshalForm(v, nil)
 		assert.NoError(t, err)
-		encoded, err := url.QueryUnescape(marshalled.Encode())
+		encoded, err := url.QueryUnescape(marshaled.Encode())
 		assert.NoError(t, err)
 		assert.Equal(t, k, encoded)
 	}
diff --git a/pkg/testutil/request_helpers.go b/pkg/testutil/request_helpers.go
index e54f535..e0f8c08 100644
--- a/pkg/testutil/request_helpers.go
+++ b/pkg/testutil/request_helpers.go
@@ -14,7 +14,7 @@
 package testutil
 
 // This is a set of fluent request builders for tests, which help us to
-// simplify constructing and unmarshalling test objects. For example, to post
+// simplify constructing and unmarshaling test objects. For example, to post
 // a body and return a response, you would do something like:
 //
 //   var body RequestBody