Repository: swaggest/rest
Pull request #167 (2023-08-08 23:16:23)

Update openapi-go

github-actions[bot]: ### Lines Of Code

| Language  |   Files   |    Lines     |    Code     | Comments  |   Blanks    | Complexity |      Bytes      |
|-----------|-----------|--------------|-------------|-----------|-------------|------------|-----------------|
| Go        | 110 (-22) | 8178 (-1319) | 5927 (-984) | 566 (-53) | 1685 (-282) | 998 (-83)  | 198.8K (-33.1K) |
| Go (test) | 53 (-10)  | 6308 (-666)  | 4834 (-498) | 291 (-32) | 1183 (-136) | 186 (-37)  | 174K (-19.4K)   |
| JSON      | 3 (-1)    | 1578 (-814)  | 1578 (-814) | 0         | 0           | 0          | 62.3K (-36K)    |
<!-- Sticky Pull Request CommentLOC -->
github-actions[bot]: ### Go API Changes

<pre>
# summary
Inferred base version: v0.2.55
Suggested version: v0.2.56
</pre>
<!-- Sticky Pull Request Commentgorelease -->
github-actions[bot]: ### Unit Test Coverage
total:								(statements)			81.4%

<details><summary>Coverage of changed lines</summary>

No changes in testable statements.

</details>

<details><summary>Coverage diff with base branch</summary>

No changes in coverage.

</details>
<!-- Sticky Pull Request Commentunit-test -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/swaggest/rest/pull/167?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) Report
> Merging [#167](https://app.codecov.io/gh/swaggest/rest/pull/167?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) (8afb41d) into [master](https://app.codecov.io/gh/swaggest/rest/commit/82f352f4db33e31fd1ef0dbb216e9712a4a4196d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) (82f352f) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##           master     #167   +/-   ##
=======================================
  Coverage   76.62%   76.62%           
=======================================
  Files          30       30           
  Lines        1673     1673           
=======================================
  Hits         1282     1282           
  Misses        284      284           
  Partials      107      107           
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `76.62% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest#carryforward-flags-in-the-pull-request-comment) to find out more.


:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest)


Patch:
diff --git a/_examples/advanced-generic/dummy.go b/_examples/advanced-generic/dummy.go
deleted file mode 100644
index f9d2db5..0000000
--- a/_examples/advanced-generic/dummy.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func dummy() usecase.Interactor {
-	u := usecase.NewInteractor(func(ctx context.Context, input struct{}, output *struct{}) error {
-		return nil
-	})
-	u.SetTags("Other")
-
-	return u
-}
diff --git a/_examples/advanced-generic/error_response.go b/_examples/advanced-generic/error_response.go
deleted file mode 100644
index 2fa2352..0000000
--- a/_examples/advanced-generic/error_response.go
+++ /dev/null
@@ -1,57 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"errors"
-
-	"github.com/bool64/ctxd"
-	"github.com/swaggest/usecase"
-	"github.com/swaggest/usecase/status"
-)
-
-type customErr struct {
-	Message string                 `json:"msg"`
-	Details map[string]interface{} `json:"details,omitempty"`
-}
-
-func errorResponse() usecase.Interactor {
-	type errType struct {
-		Type string `query:"type" enum:"ok,invalid_argument,conflict" required:"true"`
-	}
-
-	type okResp struct {
-		Status string `json:"status"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in errType, out *okResp) (err error) {
-		switch in.Type {
-		case "ok":
-			out.Status = "ok"
-		case "invalid_argument":
-			return status.Wrap(errors.New("bad value for foo"), status.InvalidArgument)
-		case "conflict":
-			return status.Wrap(ctxd.NewError(ctx, "conflict", "foo", "bar"),
-				status.AlreadyExists)
-		}
-
-		return nil
-	})
-
-	u.SetTitle("Declare Expected Errors")
-	u.SetDescription("This use case demonstrates documentation of expected errors.")
-	u.SetExpectedErrors(status.InvalidArgument, anotherErr{}, status.FailedPrecondition, status.AlreadyExists)
-	u.SetTags("Response")
-
-	return u
-}
-
-// anotherErr is another custom error.
-type anotherErr struct {
-	Foo int `json:"foo"`
-}
-
-func (anotherErr) Error() string {
-	return "foo happened"
-}
diff --git a/_examples/advanced-generic/file_multi_upload.go b/_examples/advanced-generic/file_multi_upload.go
deleted file mode 100644
index 006d5c0..0000000
--- a/_examples/advanced-generic/file_multi_upload.go
+++ /dev/null
@@ -1,78 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"mime/multipart"
-	"net/textproto"
-
-	"github.com/swaggest/usecase"
-)
-
-func fileMultiUploader() usecase.Interactor {
-	type upload struct {
-		Simple   string                  `formData:"simple" description:"Simple scalar value in body."`
-		Query    int                     `query:"in_query" description:"Simple scalar value in query."`
-		Uploads1 []*multipart.FileHeader `formData:"uploads1" description:"Uploads with *multipart.FileHeader."`
-		Uploads2 []multipart.File        `formData:"uploads2" description:"Uploads with multipart.File."`
-	}
-
-	type info struct {
-		Filenames    []string               `json:"filenames"`
-		Headers      []textproto.MIMEHeader `json:"headers"`
-		Sizes        []int64                `json:"sizes"`
-		Upload1Peeks []string               `json:"peeks1"`
-		Upload2Peeks []string               `json:"peeks2"`
-		Simple       string                 `json:"simple"`
-		Query        int                    `json:"inQuery"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in upload, out *info) (err error) {
-		out.Query = in.Query
-		out.Simple = in.Simple
-		for _, o := range in.Uploads1 {
-			out.Filenames = append(out.Filenames, o.Filename)
-			out.Headers = append(out.Headers, o.Header)
-			out.Sizes = append(out.Sizes, o.Size)
-
-			f, err := o.Open()
-			if err != nil {
-				return err
-			}
-			p := make([]byte, 100)
-			_, err = f.Read(p)
-			if err != nil {
-				return err
-			}
-
-			out.Upload1Peeks = append(out.Upload1Peeks, string(p))
-
-			err = f.Close()
-			if err != nil {
-				return err
-			}
-		}
-
-		for _, o := range in.Uploads2 {
-			p := make([]byte, 100)
-			_, err = o.Read(p)
-			if err != nil {
-				return err
-			}
-
-			out.Upload2Peeks = append(out.Upload2Peeks, string(p))
-			err = o.Close()
-			if err != nil {
-				return err
-			}
-		}
-
-		return nil
-	})
-
-	u.SetTitle("Files Uploads With 'multipart/form-data'")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/file_upload.go b/_examples/advanced-generic/file_upload.go
deleted file mode 100644
index be820a2..0000000
--- a/_examples/advanced-generic/file_upload.go
+++ /dev/null
@@ -1,82 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"mime/multipart"
-	"net/textproto"
-
-	"github.com/swaggest/usecase"
-)
-
-func fileUploader() usecase.Interactor {
-	type upload struct {
-		Simple  string                `formData:"simple" description:"Simple scalar value in body."`
-		Query   int                   `query:"in_query" description:"Simple scalar value in query."`
-		Upload1 *multipart.FileHeader `formData:"upload1" description:"Upload with *multipart.FileHeader."`
-		Upload2 multipart.File        `formData:"upload2" description:"Upload with multipart.File."`
-	}
-
-	type info struct {
-		Filename    string               `json:"filename"`
-		Header      textproto.MIMEHeader `json:"header"`
-		Size        int64                `json:"size"`
-		Upload1Peek string               `json:"peek1"`
-		Upload2Peek string               `json:"peek2"`
-		Simple      string               `json:"simple"`
-		Query       int                  `json:"inQuery"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in upload, out *info) (err error) {
-		out.Query = in.Query
-		out.Simple = in.Simple
-		if in.Upload1 == nil {
-			return nil
-		}
-
-		out.Filename = in.Upload1.Filename
-		out.Header = in.Upload1.Header
-		out.Size = in.Upload1.Size
-
-		f, err := in.Upload1.Open()
-		if err != nil {
-			return err
-		}
-
-		defer func() {
-			clErr := f.Close()
-			if clErr != nil && err == nil {
-				err = clErr
-			}
-
-			clErr = in.Upload2.Close()
-			if clErr != nil && err == nil {
-				err = clErr
-			}
-		}()
-
-		p := make([]byte, 100)
-		_, err = f.Read(p)
-		if err != nil {
-			return err
-		}
-
-		out.Upload1Peek = string(p)
-
-		p = make([]byte, 100)
-		_, err = in.Upload2.Read(p)
-		if err != nil {
-			return err
-		}
-
-		out.Upload2Peek = string(p)
-
-		return nil
-	})
-
-	u.SetTitle("File Upload With 'multipart/form-data'")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/form.go b/_examples/advanced-generic/form.go
deleted file mode 100644
index ffdfa28..0000000
--- a/_examples/advanced-generic/form.go
+++ /dev/null
@@ -1,35 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func form() usecase.Interactor {
-	type form struct {
-		ID   int    `form:"id"`
-		Name string `form:"name"`
-	}
-
-	type output struct {
-		ID   int    `json:"id"`
-		Name string `json:"name"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in form, out *output) error {
-		out.ID = in.ID
-		out.Name = in.Name
-
-		return nil
-	})
-
-	u.SetTitle("Request With Form")
-	u.SetDescription("The `form` field tag acts as `query` and `formData`, with priority on `formData`.\n\n" +
-		"It is decoded with `http.Request.Form` values.")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/gzip_pass_through.go b/_examples/advanced-generic/gzip_pass_through.go
deleted file mode 100644
index f09d3b7..0000000
--- a/_examples/advanced-generic/gzip_pass_through.go
+++ /dev/null
@@ -1,92 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/rest/gzip"
-	"github.com/swaggest/usecase"
-)
-
-type gzipPassThroughInput struct {
-	PlainStruct bool `query:"plainStruct" description:"Output plain structure instead of gzip container."`
-	CountItems  bool `query:"countItems" description:"Invokes internal decoding of compressed data."`
-}
-
-// gzipPassThroughOutput defers data to an accessor function instead of using struct directly.
-// This is necessary to allow containers that can data in binary wire-friendly format.
-type gzipPassThroughOutput interface {
-	// Data should be accessed though an accessor to allow container interface.
-	gzipPassThroughStruct() gzipPassThroughStruct
-}
-
-// gzipPassThroughStruct represents the actual structure that is held in the container
-// and implements gzipPassThroughOutput to be directly useful in output.
-type gzipPassThroughStruct struct {
-	Header string   `header:"X-Header" json:"-"`
-	ID     int      `json:"id"`
-	Text   []string `json:"text"`
-}
-
-func (d gzipPassThroughStruct) gzipPassThroughStruct() gzipPassThroughStruct {
-	return d
-}
-
-// gzipPassThroughContainer is wrapping gzip.JSONContainer and implements gzipPassThroughOutput.
-type gzipPassThroughContainer struct {
-	Header string `header:"X-Header" json:"-"`
-	gzip.JSONContainer
-}
-
-func (dc gzipPassThroughContainer) gzipPassThroughStruct() gzipPassThroughStruct {
-	var p gzipPassThroughStruct
-
-	err := dc.UnpackJSON(&p)
-	if err != nil {
-		panic(err)
-	}
-
-	return p
-}
-
-func directGzip() usecase.Interactor {
-	// Prepare moderately big JSON, resulting JSON payload is ~67KB.
-	rawData := gzipPassThroughStruct{
-		ID: 123,
-	}
-	for i := 0; i < 400; i++ {
-		rawData.Text = append(rawData.Text, "Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, "+
-			"quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?")
-	}
-
-	// Precompute compressed data container. Generally this step should be owned by a caching storage of data.
-	dataFromCache := gzipPassThroughContainer{}
-
-	err := dataFromCache.PackJSON(rawData)
-	if err != nil {
-		panic(err)
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in gzipPassThroughInput, out *gzipPassThroughOutput) error {
-		if in.PlainStruct {
-			o := rawData
-			o.Header = "cba"
-			*out = o
-		} else {
-			o := dataFromCache
-			o.Header = "abc"
-			*out = o
-		}
-
-		// Imitating an internal read operation on data in container.
-		if in.CountItems {
-			_ = len((*out).gzipPassThroughStruct().Text)
-		}
-
-		return nil
-	})
-	u.SetTags("Response")
-
-	return u
-}
diff --git a/_examples/advanced-generic/html_response.go b/_examples/advanced-generic/html_response.go
deleted file mode 100644
index bdf6242..0000000
--- a/_examples/advanced-generic/html_response.go
+++ /dev/null
@@ -1,70 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"html/template"
-	"io"
-
-	"github.com/swaggest/usecase"
-)
-
-type htmlResponseOutput struct {
-	ID         int
-	Filter     string
-	Title      string
-	Items      []string
-	AntiHeader bool `header:"X-Anti-Header"`
-
-	writer io.Writer
-}
-
-func (o *htmlResponseOutput) SetWriter(w io.Writer) {
-	o.writer = w
-}
-
-func (o *htmlResponseOutput) Render(tmpl *template.Template) error {
-	return tmpl.Execute(o.writer, o)
-}
-
-func htmlResponse() usecase.Interactor {
-	type htmlResponseInput struct {
-		ID     int    `path:"id"`
-		Filter string `query:"filter"`
-		Header bool   `header:"X-Header"`
-	}
-
-	const tpl = `<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="UTF-8">
-		<title>{{.Title}}</title>
-	</head>
-	<body>
-		<a href="/html-response/{{.ID}}?filter={{.Filter}}">Next {{.Title}}</a><br />
-		{{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}}
-	</body>
-</html>`
-
-	tmpl, err := template.New("htmlResponse").Parse(tpl)
-	if err != nil {
-		panic(err)
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in htmlResponseInput, out *htmlResponseOutput) (err error) {
-		out.AntiHeader = !in.Header
-		out.Filter = in.Filter
-		out.ID = in.ID + 1
-		out.Title = "Foo"
-		out.Items = []string{"foo", "bar", "baz"}
-
-		return out.Render(tmpl)
-	})
-
-	u.SetTitle("Request With HTML Response")
-	u.SetDescription("Request with templated HTML response.")
-	u.SetTags("Response")
-
-	return u
-}
diff --git a/_examples/advanced-generic/json_body.go b/_examples/advanced-generic/json_body.go
deleted file mode 100644
index 3e923dc..0000000
--- a/_examples/advanced-generic/json_body.go
+++ /dev/null
@@ -1,47 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/jsonschema-go"
-	"github.com/swaggest/usecase"
-)
-
-func jsonBody() usecase.Interactor {
-	type JSONPayload struct {
-		ID   int    `json:"id"`
-		Name string `json:"name"`
-	}
-
-	type inputWithJSON struct {
-		Header      string          `header:"X-Header" description:"Simple scalar value in header."`
-		Query       jsonschema.Date `query:"in_query" description:"Simple scalar value in query."`
-		Path        string          `path:"in-path" description:"Simple scalar value in path"`
-		NamedStruct JSONPayload     `json:"namedStruct" deprecated:"true"`
-		JSONPayload
-	}
-
-	type outputWithJSON struct {
-		Header string          `json:"inHeader"`
-		Query  jsonschema.Date `json:"inQuery" deprecated:"true"`
-		Path   string          `json:"inPath"`
-		JSONPayload
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputWithJSON, out *outputWithJSON) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Path = in.Path
-		out.JSONPayload = in.JSONPayload
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Body")
-	u.SetDescription("Request with JSON body and query/header/path params, response with JSON body and data from request.")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/json_body_manual.go b/_examples/advanced-generic/json_body_manual.go
deleted file mode 100644
index c16dd9f..0000000
--- a/_examples/advanced-generic/json_body_manual.go
+++ /dev/null
@@ -1,87 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io"
-	"log"
-	"net/http"
-
-	"github.com/go-chi/chi/v5"
-	"github.com/swaggest/jsonschema-go"
-	"github.com/swaggest/rest/request"
-	"github.com/swaggest/usecase"
-)
-
-func jsonBodyManual() usecase.Interactor {
-	type outputWithJSON struct {
-		Header string          `json:"inHeader"`
-		Query  jsonschema.Date `json:"inQuery" deprecated:"true"`
-		Path   string          `json:"inPath"`
-		JSONPayload
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputWithJSON, out *outputWithJSON) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Path = in.Path
-		out.JSONPayload = in.JSONPayload
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Body and manual decoder")
-	u.SetDescription("Request with JSON body and query/header/path params, response with JSON body and data from request.")
-	u.SetTags("Request")
-
-	return u
-}
-
-type JSONPayload struct {
-	ID   int    `json:"id"`
-	Name string `json:"name"`
-}
-
-type inputWithJSON struct {
-	Header      string          `header:"X-Header" description:"Simple scalar value in header."`
-	Query       jsonschema.Date `query:"in_query" description:"Simple scalar value in query."`
-	Path        string          `path:"in-path" description:"Simple scalar value in path"`
-	NamedStruct JSONPayload     `json:"namedStruct" deprecated:"true"`
-	JSONPayload
-}
-
-var _ request.Loader = &inputWithJSON{}
-
-func (i *inputWithJSON) LoadFromHTTPRequest(r *http.Request) (err error) {
-	defer func() {
-		if err := r.Body.Close(); err != nil {
-			log.Printf("failed to close request body: %s", err.Error())
-		}
-	}()
-
-	b, err := io.ReadAll(r.Body)
-	if err != nil {
-		return fmt.Errorf("failed to read request body: %w", err)
-	}
-
-	if err = json.Unmarshal(b, i); err != nil {
-		return fmt.Errorf("failed to unmarshal request body: %w", err)
-	}
-
-	i.Header = r.Header.Get("X-Header")
-	if err := i.Query.UnmarshalText([]byte(r.URL.Query().Get("in_query"))); err != nil {
-		return fmt.Errorf("failed to decode in_query %q: %w", r.URL.Query().Get("in_query"), err)
-	}
-
-	if routeCtx := chi.RouteContext(r.Context()); routeCtx != nil {
-		i.Path = routeCtx.URLParam("in-path")
-	} else {
-		return errors.New("missing path params in context")
-	}
-
-	return nil
-}
diff --git a/_examples/advanced-generic/json_body_validation.go b/_examples/advanced-generic/json_body_validation.go
deleted file mode 100644
index 44dcd7c..0000000
--- a/_examples/advanced-generic/json_body_validation.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func jsonBodyValidation() usecase.Interactor {
-	type JSONPayload struct {
-		ID   int    `json:"id" minimum:"100"`
-		Name string `json:"name" minLength:"3"`
-	}
-
-	type inputWithJSON struct {
-		Header string `header:"X-Header" description:"Simple scalar value in header." minLength:"3"`
-		Query  int    `query:"in_query" description:"Simple scalar value in query." minimum:"100"`
-		Path   string `path:"in-path" description:"Simple scalar value in path" minLength:"3"`
-		JSONPayload
-	}
-
-	type outputWithJSON struct {
-		Header string `json:"inHeader" minLength:"3"`
-		Query  int    `json:"inQuery" minimum:"3"`
-		Path   string `json:"inPath" minLength:"3"`
-		JSONPayload
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputWithJSON, out *outputWithJSON) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Path = in.Path
-		out.JSONPayload = in.JSONPayload
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Body and non-trivial validation")
-	u.SetDescription("Request with JSON body and query/header/path params, response with JSON body and data from request.")
-	u.SetTags("Request", "Response", "Validation")
-
-	return u
-}
diff --git a/_examples/advanced-generic/json_map_body.go b/_examples/advanced-generic/json_map_body.go
deleted file mode 100644
index fdac060..0000000
--- a/_examples/advanced-generic/json_map_body.go
+++ /dev/null
@@ -1,43 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"encoding/json"
-
-	"github.com/swaggest/usecase"
-)
-
-type JSONMapPayload map[string]float64
-
-type jsonMapReq struct {
-	Header string `header:"X-Header" description:"Simple scalar value in header."`
-	Query  int    `query:"in_query" description:"Simple scalar value in query."`
-	JSONMapPayload
-}
-
-func (j *jsonMapReq) UnmarshalJSON(data []byte) error {
-	return json.Unmarshal(data, &j.JSONMapPayload)
-}
-
-func jsonMapBody() usecase.Interactor {
-	type jsonOutput struct {
-		Header string         `json:"inHeader"`
-		Query  int            `json:"inQuery"`
-		Data   JSONMapPayload `json:"data"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in jsonMapReq, out *jsonOutput) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Data = in.JSONMapPayload
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Map In Body")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/json_param.go b/_examples/advanced-generic/json_param.go
deleted file mode 100644
index 9a58205..0000000
--- a/_examples/advanced-generic/json_param.go
+++ /dev/null
@@ -1,47 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/google/uuid"
-	"github.com/swaggest/usecase"
-)
-
-func jsonParam() usecase.Interactor {
-	type JSONPayload struct {
-		ID   int    `json:"id"`
-		Name string `json:"name"`
-	}
-
-	type inputWithJSON struct {
-		Header   string      `header:"X-Header" description:"Simple scalar value in header."`
-		Query    int         `query:"in_query" description:"Simple scalar value in query."`
-		Path     string      `path:"in-path" description:"Simple scalar value in path"`
-		Cookie   uuid.UUID   `cookie:"in_cookie" description:"UUID in cookie."`
-		Identity JSONPayload `query:"identity" description:"JSON value in query"`
-	}
-
-	type outputWithJSON struct {
-		Header string `json:"inHeader"`
-		Query  int    `json:"inQuery"`
-		Path   string `json:"inPath"`
-		JSONPayload
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputWithJSON, out *outputWithJSON) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Path = in.Path
-		out.JSONPayload = in.Identity
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Query Parameter")
-	u.SetDescription("Request with JSON body and query/header/path params, response with JSON body and data from request.")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/json_slice_body.go b/_examples/advanced-generic/json_slice_body.go
deleted file mode 100644
index 13be45c..0000000
--- a/_examples/advanced-generic/json_slice_body.go
+++ /dev/null
@@ -1,44 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"encoding/json"
-
-	"github.com/swaggest/usecase"
-)
-
-// JSONSlicePayload is an example non-scalar type without `json` tags.
-type JSONSlicePayload []int
-
-type jsonSliceReq struct {
-	Header string `header:"X-Header" description:"Simple scalar value in header."`
-	Query  int    `query:"in_query" description:"Simple scalar value in query."`
-	JSONSlicePayload
-}
-
-func (j *jsonSliceReq) UnmarshalJSON(data []byte) error {
-	return json.Unmarshal(data, &j.JSONSlicePayload)
-}
-
-func jsonSliceBody() usecase.Interactor {
-	type jsonOutput struct {
-		Header string           `json:"inHeader"`
-		Query  int              `json:"inQuery"`
-		Data   JSONSlicePayload `json:"data"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in jsonSliceReq, out *jsonOutput) (err error) {
-		out.Query = in.Query
-		out.Header = in.Header
-		out.Data = in.JSONSlicePayload
-
-		return nil
-	})
-
-	u.SetTitle("Request With JSON Array In Body")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/main.go b/_examples/advanced-generic/main.go
deleted file mode 100644
index 2821f54..0000000
--- a/_examples/advanced-generic/main.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"log"
-	"net/http"
-)
-
-func main() {
-	log.Println("http://localhost:8011/docs")
-	if err := http.ListenAndServe("localhost:8011", NewRouter()); err != nil {
-		log.Fatal(err)
-	}
-}
diff --git a/_examples/advanced-generic/no_validation.go b/_examples/advanced-generic/no_validation.go
deleted file mode 100644
index 8cc1b25..0000000
--- a/_examples/advanced-generic/no_validation.go
+++ /dev/null
@@ -1,41 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func noValidation() usecase.Interactor {
-	type inputPort struct {
-		Header int  `header:"X-Input"`
-		Query  bool `query:"q"`
-		Data   struct {
-			Value string `json:"value"`
-		} `json:"data"`
-	}
-
-	type outputPort struct {
-		Header        int  `header:"X-Output" json:"-"`
-		AnotherHeader bool `header:"X-Query" json:"-"`
-		Data          struct {
-			Value string `json:"value"`
-		} `json:"data"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputPort, out *outputPort) (err error) {
-		out.Header = in.Header
-		out.AnotherHeader = in.Query
-		out.Data.Value = in.Data.Value
-
-		return nil
-	})
-
-	u.SetTitle("No Validation")
-	u.SetDescription("Input/Output without validation.")
-	u.SetTags("Request", "Response")
-
-	return u
-}
diff --git a/_examples/advanced-generic/output_headers.go b/_examples/advanced-generic/output_headers.go
deleted file mode 100644
index 41f2227..0000000
--- a/_examples/advanced-generic/output_headers.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-	"github.com/swaggest/usecase/status"
-)
-
-func outputHeaders() usecase.Interactor {
-	type EmbeddedHeaders struct {
-		Foo int `header:"X-foO,omitempty" json:"-" minimum:"10" required:"true" description:"Reduced by 20 in response."`
-	}
-
-	type headerOutput struct {
-		EmbeddedHeaders
-		Header    string `header:"x-HeAdEr" json:"-" description:"Sample response header."`
-		OmitEmpty int    `header:"x-omit-empty,omitempty" json:"-" description:"Receives req value of X-Foo reduced by 30."`
-		InBody    string `json:"inBody" deprecated:"true"`
-		Cookie    int    `cookie:"coo,httponly,path:/foo" json:"-"`
-	}
-
-	type headerInput struct {
-		EmbeddedHeaders
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in headerInput, out *headerOutput) (err error) {
-		out.Header = "abc"
-		out.InBody = "def"
-		out.Cookie = 123
-		out.Foo = in.Foo - 20
-		out.OmitEmpty = in.Foo - 30
-
-		return nil
-	})
-
-	u.SetTitle("Output With Headers")
-	u.SetDescription("Output with headers.")
-	u.SetTags("Response")
-	u.SetExpectedErrors(status.Internal)
-
-	return u
-}
diff --git a/_examples/advanced-generic/output_writer.go b/_examples/advanced-generic/output_writer.go
deleted file mode 100644
index 61f88cc..0000000
--- a/_examples/advanced-generic/output_writer.go
+++ /dev/null
@@ -1,47 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"encoding/csv"
-	"net/http"
-
-	"github.com/swaggest/rest"
-	"github.com/swaggest/usecase"
-	"github.com/swaggest/usecase/status"
-)
-
-func outputCSVWriter() usecase.Interactor {
-	type writerOutput struct {
-		Header      string `header:"X-Header" description:"Sample response header."`
-		ContentHash string `header:"ETag" description:"Content hash."`
-		usecase.OutputWithEmbeddedWriter
-	}
-
-	type writerInput struct {
-		ContentHash string `header:"If-None-Match" description:"Content hash."`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in writerInput, out *writerOutput) (err error) {
-		contentHash := "abc123" // Pretending this is an actual content hash.
-
-		if in.ContentHash == contentHash {
-			return rest.HTTPCodeAsError(http.StatusNotModified)
-		}
-
-		out.Header = "abc"
-		out.ContentHash = contentHash
-
-		c := csv.NewWriter(out)
-
-		return c.WriteAll([][]string{{"abc", "def", "hij"}, {"klm", "nop", "qrs"}})
-	})
-
-	u.SetTitle("Output With Stream Writer")
-	u.SetDescription("Output with stream writer.")
-	u.SetExpectedErrors(status.Internal, rest.HTTPCodeAsError(http.StatusNotModified))
-	u.SetTags("Response")
-
-	return u
-}
diff --git a/_examples/advanced-generic/query_object.go b/_examples/advanced-generic/query_object.go
deleted file mode 100644
index 148f404..0000000
--- a/_examples/advanced-generic/query_object.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func queryObject() usecase.Interactor {
-	type jsonFilter struct {
-		Foo string `json:"foo" maxLength:"5"`
-	}
-
-	type deepObjectFilter struct {
-		Bar string  `json:"bar" query:"bar" minLength:"3"`
-		Baz *string `json:"baz,omitempty" query:"baz" minLength:"3"`
-	}
-
-	type inputQueryObject struct {
-		Query            map[int]float64  `query:"in_query" description:"Object value in query."`
-		JSONFilter       jsonFilter       `query:"json_filter" description:"JSON object value in query."`
-		DeepObjectFilter deepObjectFilter `query:"deep_object_filter" description:"Deep object value in query params."`
-	}
-
-	type outputQueryObject struct {
-		Query            map[int]float64  `json:"inQuery"`
-		JSONFilter       jsonFilter       `json:"jsonFilter"`
-		DeepObjectFilter deepObjectFilter `json:"deepObjectFilter"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputQueryObject, out *outputQueryObject) (err error) {
-		out.Query = in.Query
-		out.JSONFilter = in.JSONFilter
-		out.DeepObjectFilter = in.DeepObjectFilter
-
-		return nil
-	})
-
-	u.SetTitle("Request With Object As Query Parameter")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/request_response_mapping.go b/_examples/advanced-generic/request_response_mapping.go
deleted file mode 100644
index 39a5d7d..0000000
--- a/_examples/advanced-generic/request_response_mapping.go
+++ /dev/null
@@ -1,35 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func reqRespMapping() usecase.Interactor {
-	type inputPort struct {
-		Val1 string `description:"Simple scalar value with sample validation." required:"true" minLength:"3"`
-		Val2 int    `description:"Simple scalar value with sample validation." required:"true" minimum:"3"`
-	}
-
-	type outputPort struct {
-		Val1 string `json:"-" description:"Simple scalar value with sample validation." required:"true" minLength:"3"`
-		Val2 int    `json:"-" description:"Simple scalar value with sample validation." required:"true" minimum:"3"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputPort, out *outputPort) (err error) {
-		out.Val1 = in.Val1
-		out.Val2 = in.Val2
-
-		return nil
-	})
-
-	u.SetTitle("Request Response Mapping")
-	u.SetName("reqRespMapping")
-	u.SetDescription("This use case has transport concerns fully decoupled with external req/resp mapping.")
-	u.SetTags("Request", "Response")
-
-	return u
-}
diff --git a/_examples/advanced-generic/request_text_body.go b/_examples/advanced-generic/request_text_body.go
deleted file mode 100644
index 38b8240..0000000
--- a/_examples/advanced-generic/request_text_body.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package main
-
-import (
-	"context"
-	"io"
-	"net/http"
-
-	"github.com/swaggest/usecase"
-)
-
-type textReqBodyInput struct {
-	Path  string `path:"path"`
-	Query int    `query:"query"`
-	text  []byte
-	err   error
-}
-
-func (c *textReqBodyInput) SetRequest(r *http.Request) {
-	c.text, c.err = io.ReadAll(r.Body)
-	clErr := r.Body.Close()
-
-	if c.err == nil {
-		c.err = clErr
-	}
-}
-
-func textReqBody() usecase.Interactor {
-	type output struct {
-		Path  string `json:"path"`
-		Query int    `json:"query"`
-		Text  string `json:"text"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in textReqBodyInput, out *output) (err error) {
-		out.Text = string(in.text)
-		out.Path = in.Path
-		out.Query = in.Query
-
-		return nil
-	})
-
-	u.SetTitle("Request With Text Body")
-	u.SetDescription("This usecase allows direct access to original `*http.Request` while keeping automated decoding of parameters.")
-	u.SetTags("Request")
-
-	return u
-}
-
-func textReqBodyPtr() usecase.Interactor {
-	type output struct {
-		Path  string `json:"path"`
-		Query int    `json:"query"`
-		Text  string `json:"text"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in *textReqBodyInput, out *output) (err error) {
-		out.Text = string(in.text)
-		out.Path = in.Path
-		out.Query = in.Query
-
-		return nil
-	})
-
-	u.SetTitle("Request With Text Body (ptr input)")
-	u.SetDescription("This usecase allows direct access to original `*http.Request` while keeping automated decoding of parameters.")
-	u.SetTags("Request")
-
-	return u
-}
diff --git a/_examples/advanced-generic/router.go b/_examples/advanced-generic/router.go
deleted file mode 100644
index 87d93b4..0000000
--- a/_examples/advanced-generic/router.go
+++ /dev/null
@@ -1,238 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-	"errors"
-	"log"
-	"net/http"
-	"reflect"
-	"strings"
-
-	"github.com/go-chi/chi/v5"
-	"github.com/google/uuid"
-	"github.com/rs/cors"
-	"github.com/swaggest/jsonschema-go"
-	oapi "github.com/swaggest/openapi-go"
-	"github.com/swaggest/openapi-go/openapi3"
-	"github.com/swaggest/rest"
-	"github.com/swaggest/rest/nethttp"
-	"github.com/swaggest/rest/response"
-	"github.com/swaggest/rest/response/gzip"
-	"github.com/swaggest/rest/web"
-	swgui "github.com/swaggest/swgui/v5emb"
-	"github.com/swaggest/usecase"
-)
-
-func NewRouter() http.Handler {
-	s := web.NewService(openapi3.NewReflector())
-
-	s.OpenAPISchema().SetTitle("Advanced Example")
-	s.OpenAPISchema().SetDescription("This app showcases a variety of features.")
-	s.OpenAPISchema().SetVersion("v1.2.3")
-
-	jsr := s.OpenAPIReflector().JSONSchemaReflector()
-
-	jsr.DefaultOptions = append(jsr.DefaultOptions, jsonschema.InterceptDefName(
-		func(t reflect.Type, defaultDefName string) string {
-			return strings.ReplaceAll(defaultDefName, "Generic", "")
-		},
-	))
-
-	// Usecase middlewares can be added to web.Service or chirouter.Wrapper.
-	s.Wrap(nethttp.UseCaseMiddlewares(usecase.MiddlewareFunc(func(next usecase.Interactor) usecase.Interactor {
-		var (
-			hasName usecase.HasName
-			name    = "unknown"
-		)
-
-		if usecase.As(next, &hasName) {
-			name = hasName.Name()
-		}
-
-		return usecase.Interact(func(ctx context.Context, input, output interface{}) error {
-			err := next.Interact(ctx, input, output)
-			if err != nil && !errors.Is(err, rest.HTTPCodeAsError(http.StatusNotModified)) {
-				log.Printf("usecase %s request (%+v) failed: %v\n", name, input, err)
-			}
-
-			return err
-		})
-	})))
-
-	// An example of global schema override to disable additionalProperties for all object schemas.
-	jsr.DefaultOptions = append(jsr.DefaultOptions,
-		jsonschema.InterceptSchema(func(params jsonschema.InterceptSchemaParams) (stop bool, err error) {
-			// Allow unknown request headers and skip response.
-			if oc, ok := oapi.OperationCtx(params.Context); !params.Processed || !ok ||
-				oc.IsProcessingResponse() || oc.ProcessingIn() == oapi.InHeader {
-				return false, nil
-			}
-
-			schema := params.Schema
-
-			if schema.HasType(jsonschema.Object) && len(schema.Properties) > 0 && schema.AdditionalProperties == nil {
-				schema.AdditionalProperties = (&jsonschema.SchemaOrBool{}).WithTypeBoolean(false)
-			}
-
-			return false, nil
-		}),
-	)
-
-	// Create custom schema mapping for 3rd party type.
-	uuidDef := jsonschema.Schema{}
-	uuidDef.AddType(jsonschema.String)
-	uuidDef.WithFormat("uuid")
-	uuidDef.WithExamples("248df4b7-aa70-47b8-a036-33ac447e668d")
-	jsr.AddTypeMapping(uuid.UUID{}, uuidDef)
-
-	// When multiple structures can be returned with the same HTTP status code, it is possible to combine them into a
-	// single schema with such configuration.
-	s.OpenAPICollector.CombineErrors = "anyOf"
-
-	s.Wrap(
-		// Example middleware to set up custom error responses and disable response validation for particular handlers.
-		func(handler http.Handler) http.Handler {
-			var h *nethttp.Handler
-			if nethttp.HandlerAs(handler, &h) {
-				h.MakeErrResp = func(ctx context.Context, err error) (int, interface{}) {
-					code, er := rest.Err(err)
-
-					var ae anotherErr
-
-					if errors.As(err, &ae) {
-						return http.StatusBadRequest, ae
-					}
-
-					return code, customErr{
-						Message: er.ErrorText,
-						Details: er.Context,
-					}
-				}
-
-				var hr rest.HandlerWithRoute
-				if h.RespValidator != nil &&
-					nethttp.HandlerAs(handler, &hr) {
-					if hr.RoutePattern() == "/json-body-manual/{in-path}" || hr.RoutePattern() == "/json-body/{in-path}" {
-						h.RespValidator = nil
-					}
-				}
-			}
-
-			return handler
-		},
-
-		// Example middleware to set up CORS headers.
-		// See https://pkg.go.dev/github.com/rs/cors for more details.
-		cors.AllowAll().Handler,
-
-		// Response validator setup.
-		//
-		// It might be a good idea to disable this middleware in production to save performance,
-		// but keep it enabled in dev/test/staging environments to catch logical issues.
-		response.ValidatorMiddleware(s.ResponseValidatorFactory),
-		gzip.Middleware, // Response compression with support for direct gzip pass through.
-	)
-
-	// Annotations can be used to alter documentation of operation identified by method and path.
-	s.OpenAPICollector.AnnotateOperation(http.MethodPost, "/validation", func(oc oapi.OperationContext) error {
-		o3, ok := oc.(openapi3.OperationExposer)
-		if !ok {
-			return nil
-		}
-
-		op := o3.Operation()
-
-		if op.Description != nil {
-			*op.Description = *op.Description + " Custom annotation."
-		}
-
-		return nil
-	})
-
-	s.Get("/query-object", queryObject())
-	s.Post("/form", form())
-
-	s.Post("/file-upload", fileUploader())
-	s.Post("/file-multi-upload", fileMultiUploader())
-	s.Get("/json-param/{in-path}", jsonParam())
-	s.Post("/json-body/{in-path}", jsonBody(),
-		nethttp.SuccessStatus(http.StatusCreated))
-	s.Post("/json-body-manual/{in-path}", jsonBodyManual(),
-		nethttp.SuccessStatus(http.StatusCreated))
-	s.Post("/json-body-validation/{in-path}", jsonBodyValidation())
-	s.Post("/json-slice-body", jsonSliceBody())
-
-	s.Post("/json-map-body", jsonMapBody(),
-		// Annotate operation to add post-processing if necessary.
-		nethttp.AnnotateOpenAPIOperation(func(oc oapi.OperationContext) error {
-			oc.SetDescription("Request with JSON object (map) body.")
-
-			return nil
-		}))
-
-	s.Get("/html-response/{id}", htmlResponse(), nethttp.SuccessfulResponseContentType("text/html"))
-
-	s.Get("/output-headers", outputHeaders())
-	s.Head("/output-headers", outputHeaders())
-	s.Get("/output-csv-writer", outputCSVWriter(),
-		nethttp.SuccessfulResponseContentType("text/csv; charset=utf-8"))
-
-	s.Post("/req-resp-mapping", reqRespMapping(),
-		nethttp.RequestMapping(new(struct {
-			Val1 string `header:"X-Header"`
-			Val2 int    `formData:"val2"`
-		})),
-		nethttp.ResponseHeaderMapping(new(struct {
-			Val1 string `header:"X-Value-1"`
-			Val2 int    `header:"X-Value-2"`
-		})),
-	)
-
-	s.Post("/validation", validation())
-	s.Post("/no-validation", noValidation())
-
-	// Type mapping is necessary to pass interface as structure into documentation.
-	jsr.AddTypeMapping(new(gzipPassThroughOutput), new(gzipPassThroughStruct))
-	s.Get("/gzip-pass-through", directGzip())
-	s.Head("/gzip-pass-through", directGzip())
-
-	s.Get("/error-response", errorResponse())
-	s.Post("/text-req-body/{path}", textReqBody(), nethttp.RequestBodyContent("text/csv"))
-	s.Post("/text-req-body-ptr/{path}", textReqBodyPtr(), nethttp.RequestBodyContent("text/csv"))
-
-	// Security middlewares.
-	//  - sessMW is the actual request-level processor,
-	//  - sessDoc is a handler-level wrapper to expose docs.
-	sessMW := func(handler http.Handler) http.Handler {
-		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-			if c, err := r.Cookie("sessid"); err == nil {
-				r = r.WithContext(context.WithValue(r.Context(), "sessionID", c.Value))
-			}
-
-			handler.ServeHTTP(w, r)
-		})
-	}
-
-	sessDoc := nethttp.AuthMiddleware(s.OpenAPICollector, "User")
-	s.OpenAPISchema().SetAPIKeySecurity("User", "sessid", oapi.InCookie, "Session cookie.")
-
-	// Security schema is configured for a single top-level route.
-	s.With(sessMW, sessDoc).Method(http.MethodGet, "/root-with-session", nethttp.NewHandler(dummy()))
-
-	// Security schema is configured on a sub-router.
-	s.Route("/deeper-with-session", func(r chi.Router) {
-		r.Group(func(r chi.Router) {
-			r.Use(sessMW, sessDoc)
-
-			r.Method(http.MethodGet, "/one", nethttp.NewHandler(dummy()))
-			r.Method(http.MethodGet, "/two", nethttp.NewHandler(dummy()))
-		})
-	})
-
-	// Swagger UI endpoint at /docs.
-	s.Docs("/docs", swgui.New)
-
-	return s
-}
diff --git a/_examples/advanced-generic/validation.go b/_examples/advanced-generic/validation.go
deleted file mode 100644
index f4e66c5..0000000
--- a/_examples/advanced-generic/validation.go
+++ /dev/null
@@ -1,41 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"context"
-
-	"github.com/swaggest/usecase"
-)
-
-func validation() usecase.Interactor {
-	type inputPort struct {
-		Header int  `header:"X-Input" minimum:"10" description:"Request minimum: 10, response maximum: 20."`
-		Query  bool `query:"q" description:"This parameter will bypass explicit validation as it does not have constraints."`
-		Data   struct {
-			Value string `json:"value" minLength:"3" description:"Request minLength: 3, response maxLength: 7"`
-		} `json:"data" required:"true"`
-	}
-
-	type outputPort struct {
-		Header        int  `header:"X-Output" json:"-" maximum:"20"`
-		AnotherHeader bool `header:"X-Query" json:"-" description:"This header bypasses validation as it does not have constraints."`
-		Data          struct {
-			Value string `json:"value" maxLength:"7"`
-		} `json:"data" required:"true"`
-	}
-
-	u := usecase.NewInteractor(func(ctx context.Context, in inputPort, out *outputPort) (err error) {
-		out.Header = in.Header
-		out.AnotherHeader = in.Query
-		out.Data.Value = in.Data.Value
-
-		return nil
-	})
-
-	u.SetTitle("Validation")
-	u.SetDescription("Input/Output with validation.")
-	u.SetTags("Request", "Response", "Validation")
-
-	return u
-}
diff --git a/_examples/go.mod b/_examples/go.mod
index 8f9ea40..b5a0a22 100644
--- a/_examples/go.mod
+++ b/_examples/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/stretchr/testify v1.8.4
 	github.com/swaggest/assertjson v1.9.0
 	github.com/swaggest/jsonschema-go v0.3.57
-	github.com/swaggest/openapi-go v0.2.38
+	github.com/swaggest/openapi-go v0.2.39
 	github.com/swaggest/rest v0.0.0-00010101000000-000000000000
 	github.com/swaggest/swgui v1.7.2
 	github.com/swaggest/usecase v1.2.1
diff --git a/_examples/go.sum b/_examples/go.sum
index ab45a43..6ee6891 100644
--- a/_examples/go.sum
+++ b/_examples/go.sum
@@ -106,8 +106,8 @@ github.com/swaggest/form/v5 v5.1.1 h1:ct6/rOQBGrqWUQ0FUv3vW5sHvTUb31AwTUWj947N6c
 github.com/swaggest/form/v5 v5.1.1/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg=
 github.com/swaggest/jsonschema-go v0.3.57 h1:n6D/2K9557Yqn/NohXoszmjuN0Lp5n0DyHlVLRZXbOM=
 github.com/swaggest/jsonschema-go v0.3.57/go.mod h1:5WFFGBBte5JAWAV8gDpNRJ/tlQnb1AHDdf/ghgsVUik=
-github.com/swaggest/openapi-go v0.2.38 h1:umFRZ2wg75eDAofQCMLfXf8eWBLuQNfU9jOjGxwFdng=
-github.com/swaggest/openapi-go v0.2.38/go.mod h1:g+AfRIkPCHdhqfW8zOD1Sk3PwLhxpWW8SNWHXrmA08c=
+github.com/swaggest/openapi-go v0.2.39 h1:GfICsAAFnQuyxfywsGyCbPqDKeMXxots4N/9j6+qSCk=
+github.com/swaggest/openapi-go v0.2.39/go.mod h1:g+AfRIkPCHdhqfW8zOD1Sk3PwLhxpWW8SNWHXrmA08c=
 github.com/swaggest/refl v1.2.0 h1:Qqqhfwi7REXF6/4cwJmj3gQMzl0Q0cYquxTYdD0kvi0=
 github.com/swaggest/refl v1.2.0/go.mod h1:CkC6g7h1PW33KprTuYRSw8UUOslRUt4lF3oe7tTIgNU=
 github.com/swaggest/swgui v1.7.2 h1:N5hMPCQ+bIedVJoQDNjFUn8BqtISQDwaqEa76VkvzLs=
diff --git a/go.mod b/go.mod
index 713a233..63e3f22 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,7 @@ require (
 	github.com/swaggest/assertjson v1.9.0
 	github.com/swaggest/form/v5 v5.1.1
 	github.com/swaggest/jsonschema-go v0.3.57
-	github.com/swaggest/openapi-go v0.2.38
+	github.com/swaggest/openapi-go v0.2.39
 	github.com/swaggest/refl v1.2.0
 	github.com/swaggest/usecase v1.2.1
 )
diff --git a/go.sum b/go.sum
index a8336a8..9901f29 100644
--- a/go.sum
+++ b/go.sum
@@ -80,6 +80,10 @@ github.com/swaggest/jsonschema-go v0.3.57 h1:n6D/2K9557Yqn/NohXoszmjuN0Lp5n0DyHl
 github.com/swaggest/jsonschema-go v0.3.57/go.mod h1:5WFFGBBte5JAWAV8gDpNRJ/tlQnb1AHDdf/ghgsVUik=
 github.com/swaggest/openapi-go v0.2.38 h1:umFRZ2wg75eDAofQCMLfXf8eWBLuQNfU9jOjGxwFdng=
 github.com/swaggest/openapi-go v0.2.38/go.mod h1:g+AfRIkPCHdhqfW8zOD1Sk3PwLhxpWW8SNWHXrmA08c=
+github.com/swaggest/openapi-go v0.2.39-0.20230808224522-65df89a56f9b h1:z6txhy0FqQLgaD8MbWe9Zn3CHNb41IMlPKzEUFQcBdQ=
+github.com/swaggest/openapi-go v0.2.39-0.20230808224522-65df89a56f9b/go.mod h1:g+AfRIkPCHdhqfW8zOD1Sk3PwLhxpWW8SNWHXrmA08c=
+github.com/swaggest/openapi-go v0.2.39 h1:GfICsAAFnQuyxfywsGyCbPqDKeMXxots4N/9j6+qSCk=
+github.com/swaggest/openapi-go v0.2.39/go.mod h1:g+AfRIkPCHdhqfW8zOD1Sk3PwLhxpWW8SNWHXrmA08c=
 github.com/swaggest/refl v1.2.0 h1:Qqqhfwi7REXF6/4cwJmj3gQMzl0Q0cYquxTYdD0kvi0=
 github.com/swaggest/refl v1.2.0/go.mod h1:CkC6g7h1PW33KprTuYRSw8UUOslRUt4lF3oe7tTIgNU=
 github.com/swaggest/usecase v1.2.1 h1:XYVdK9tK2KCPglTflUi7aWBrVwIyb58D5mvGWED7pNs=


Test patch:
diff --git a/_examples/advanced-generic-openapi31/_testdata/openapi.json b/_examples/advanced-generic-openapi31/_testdata/openapi.json
index b539ff3..53628a7 100644
--- a/_examples/advanced-generic-openapi31/_testdata/openapi.json
+++ b/_examples/advanced-generic-openapi31/_testdata/openapi.json
@@ -305,7 +305,7 @@
      },
      {
       "name":"identity","in":"query","description":"JSON value in query",
-      "content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryAdvancedJSONPayload"}}}
+      "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJSONPayload"}}}
      },
      {
       "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
@@ -313,7 +313,7 @@
      },
      {
       "name":"in_cookie","in":"cookie","description":"UUID in cookie.",
-      "schema":{"$ref":"#/components/schemas/CookieUuidUUID","description":"UUID in cookie."}
+      "schema":{"$ref":"#/components/schemas/UuidUUID","description":"UUID in cookie."}
      },
      {
       "name":"X-Header","in":"header","description":"Simple scalar value in header.",
@@ -485,13 +485,12 @@
      },
      {
       "name":"json_filter","in":"query","description":"JSON object value in query.",
-      "content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryAdvancedJsonFilter"}}}
+      "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJsonFilter"}}}
      },
      {
       "name":"deep_object_filter","in":"query","description":"Deep object value in query params.",
       "schema":{
-       "$ref":"#/components/schemas/QueryAdvancedDeepObjectFilter",
-       "description":"Deep object value in query params."
+       "$ref":"#/components/schemas/AdvancedDeepObjectFilter","description":"Deep object value in query params."
       },
       "style":"deepObject","explode":true
      }
@@ -692,6 +691,7 @@
     "properties":{"id":{"minimum":100,"type":"integer"},"name":{"minLength":3,"type":"string"}},"type":"object"
    },
    "AdvancedJSONMapPayload":{"additionalProperties":{"type":"number"},"type":"object"},
+   "AdvancedJSONPayload":{"additionalProperties":false,"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},
    "AdvancedJSONPayloadType2":{"additionalProperties":false,"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},
    "AdvancedJSONPayloadType3":{"additionalProperties":false,"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},
    "AdvancedJSONSlicePayload":{"items":{"type":"integer"},"type":["array","null"]},
@@ -758,7 +758,6 @@
     },
     "type":"object"
    },
-   "CookieUuidUUID":{"examples":["248df4b7-aa70-47b8-a036-33ac447e668d"],"format":"uuid","type":"string"},
    "FormDataAdvancedForm":{"additionalProperties":false,"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},
    "FormDataAdvancedInputPort":{
     "additionalProperties":false,
@@ -794,13 +793,6 @@
    },
    "FormDataMultipartFile":{"format":"binary","type":["null","string"]},
    "FormDataMultipartFileHeader":{"format":"binary","type":["null","string"]},
-   "QueryAdvancedDeepObjectFilter":{
-    "additionalProperties":false,
-    "properties":{"bar":{"minLength":3,"type":"string"},"baz":{"minLength":3,"type":["null","string"]}},
-    "type":"object"
-   },
-   "QueryAdvancedJSONPayload":{"additionalProperties":false,"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},
-   "QueryAdvancedJsonFilter":{"additionalProperties":false,"properties":{"foo":{"maxLength":5,"type":"string"}},"type":"object"},
    "RestErrResponse":{
     "properties":{
      "code":{"description":"Application-specific error code.","type":"integer"},
@@ -810,7 +802,8 @@
     },
     "type":"object"
    },
-   "TextprotoMIMEHeader":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"}
+   "TextprotoMIMEHeader":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},
+   "UuidUUID":{"examples":["248df4b7-aa70-47b8-a036-33ac447e668d"],"format":"uuid","type":"string"}
   },
   "securitySchemes":{"User":{"description":"Session cookie.","type":"apiKey","name":"sessid","in":"cookie"}}
  }
diff --git a/_examples/advanced-generic/_testdata/openapi.json b/_examples/advanced-generic/_testdata/openapi.json
deleted file mode 100644
index b40ed84..0000000
--- a/_examples/advanced-generic/_testdata/openapi.json
+++ /dev/null
@@ -1,807 +0,0 @@
-{
-  "openapi":"3.0.3",
-  "info":{"title":"Advanced Example","description":"This app showcases a variety of features.","version":"v1.2.3"},
-  "paths":{
-    "/deeper-with-session/one":{
-      "get":{
-        "tags":["Other"],"summary":"Dummy","operationId":"_examples/advanced-generic.dummy2",
-        "responses":{
-          "204":{"description":"No Content"},
-          "401":{
-            "description":"Unauthorized",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestErrResponse"}}}
-          }
-        },
-        "security":[{"User":[]}]
-      }
-    },
-    "/deeper-with-session/two":{
-      "get":{
-        "tags":["Other"],"summary":"Dummy","operationId":"_examples/advanced-generic.dummy3",
-        "responses":{
-          "204":{"description":"No Content"},
-          "401":{
-            "description":"Unauthorized",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestErrResponse"}}}
-          }
-        },
-        "security":[{"User":[]}]
-      }
-    },
-    "/error-response":{
-      "get":{
-        "tags":["Response"],"summary":"Declare Expected Errors",
-        "description":"This use case demonstrates documentation of expected errors.",
-        "operationId":"_examples/advanced-generic.errorResponse",
-        "parameters":[
-          {
-            "name":"type","in":"query","required":true,
-            "schema":{"enum":["ok","invalid_argument","conflict"],"type":"string"}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOkResp"}}}
-          },
-          "400":{
-            "description":"Bad Request",
-            "content":{
-              "application/json":{
-                "schema":{
-                  "anyOf":[
-                    {"$ref":"#/components/schemas/AdvancedCustomErr"},
-                    {"$ref":"#/components/schemas/AdvancedAnotherErr"}
-                  ]
-                }
-              }
-            }
-          },
-          "409":{
-            "description":"Conflict",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedCustomErr"}}}
-          },
-          "412":{
-            "description":"Precondition Failed",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedCustomErr"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/file-multi-upload":{
-      "post":{
-        "tags":["Request"],"summary":"Files Uploads With 'multipart/form-data'",
-        "operationId":"_examples/advanced-generic.fileMultiUploader",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","description":"Simple scalar value in query."}
-          }
-        ],
-        "requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FormDataAdvancedUploadType2"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInfoType2"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/file-upload":{
-      "post":{
-        "tags":["Request"],"summary":"File Upload With 'multipart/form-data'",
-        "operationId":"_examples/advanced-generic.fileUploader",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","description":"Simple scalar value in query."}
-          }
-        ],
-        "requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FormDataAdvancedUpload"}}}},
-        "responses":{
-          "200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInfo"}}}}
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/form":{
-      "post":{
-        "tags":["Request"],"summary":"Request With Form",
-        "description":"The `form` field tag acts as `query` and `formData`, with priority on `formData`.\n\nIt is decoded with `http.Request.Form` values.",
-        "operationId":"_examples/advanced-generic.form",
-        "parameters":[
-          {"name":"id","in":"query","schema":{"type":"integer"}},
-          {"name":"name","in":"query","schema":{"type":"string"}}
-        ],
-        "requestBody":{
-          "content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/FormDataAdvancedForm"}}}
-        },
-        "responses":{
-          "200":{
-            "description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutput"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/gzip-pass-through":{
-      "get":{
-        "tags":["Response"],"summary":"Direct Gzip","operationId":"_examples/advanced-generic.directGzip",
-        "parameters":[
-          {
-            "name":"plainStruct","in":"query","description":"Output plain structure instead of gzip container.",
-            "schema":{"type":"boolean","description":"Output plain structure instead of gzip container."}
-          },
-          {
-            "name":"countItems","in":"query","description":"Invokes internal decoding of compressed data.",
-            "schema":{"type":"boolean","description":"Invokes internal decoding of compressed data."}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK","headers":{"X-Header":{"style":"simple","schema":{"type":"string"}}},
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedGzipPassThroughStruct"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      },
-      "head":{
-        "tags":["Response"],"summary":"Direct Gzip","operationId":"_examples/advanced-generic.directGzip2",
-        "parameters":[
-          {
-            "name":"plainStruct","in":"query","description":"Output plain structure instead of gzip container.",
-            "schema":{"type":"boolean","description":"Output plain structure instead of gzip container."}
-          },
-          {
-            "name":"countItems","in":"query","description":"Invokes internal decoding of compressed data.",
-            "schema":{"type":"boolean","description":"Invokes internal decoding of compressed data."}
-          }
-        ],
-        "responses":{"200":{"description":"OK","headers":{"X-Header":{"style":"simple","schema":{"type":"string"}}}}},
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/html-response/{id}":{
-      "get":{
-        "tags":["Response"],"summary":"Request With HTML Response",
-        "description":"Request with templated HTML response.","operationId":"_examples/advanced-generic.htmlResponse",
-        "parameters":[
-          {"name":"filter","in":"query","schema":{"type":"string"}},
-          {"name":"id","in":"path","required":true,"schema":{"type":"integer"}},
-          {"name":"X-Header","in":"header","schema":{"type":"boolean"}}
-        ],
-        "responses":{
-          "200":{
-            "description":"OK","headers":{"X-Anti-Header":{"style":"simple","schema":{"type":"boolean"}}},
-            "content":{"text/html":{"schema":{"type":"string"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/json-body-manual/{in-path}":{
-      "post":{
-        "tags":["Request"],"summary":"Request With JSON Body and manual decoder",
-        "description":"Request with JSON body and query/header/path params, response with JSON body and data from request.",
-        "operationId":"_examples/advanced-generic.jsonBodyManual",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"string","description":"Simple scalar value in query.","format":"date"}
-          },
-          {
-            "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
-            "schema":{"type":"string","description":"Simple scalar value in path"}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInputWithJSONType3"}}}},
-        "responses":{
-          "201":{
-            "description":"Created",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputWithJSONType3"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/json-body-validation/{in-path}":{
-      "post":{
-        "tags":["Request","Response","Validation"],"summary":"Request With JSON Body and non-trivial validation",
-        "description":"Request with JSON body and query/header/path params, response with JSON body and data from request.",
-        "operationId":"_examples/advanced-generic.jsonBodyValidation",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"minimum":100,"type":"integer","description":"Simple scalar value in query."}
-          },
-          {
-            "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
-            "schema":{"minLength":3,"type":"string","description":"Simple scalar value in path"}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"minLength":3,"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInputWithJSONType4"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputWithJSONType4"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/json-body/{in-path}":{
-      "post":{
-        "tags":["Request"],"summary":"Request With JSON Body",
-        "description":"Request with JSON body and query/header/path params, response with JSON body and data from request.",
-        "operationId":"_examples/advanced-generic.jsonBody",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"string","description":"Simple scalar value in query.","format":"date"}
-          },
-          {
-            "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
-            "schema":{"type":"string","description":"Simple scalar value in path"}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInputWithJSONType2"}}}},
-        "responses":{
-          "201":{
-            "description":"Created",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputWithJSONType2"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/json-map-body":{
-      "post":{
-        "tags":["Request"],"summary":"Request With JSON Map In Body",
-        "description":"Request with JSON object (map) body.","operationId":"_examples/advanced-generic.jsonMapBody",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","description":"Simple scalar value in query."}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJsonMapReq"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJsonOutputType2"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/json-param/{in-path}":{
-      "get":{
-        "tags":["Request"],"summary":"Request With JSON Query Parameter",
-        "description":"Request with JSON body and query/header/path params, response with JSON body and data from request.",
-        "operationId":"_examples/advanced-generic.jsonParam",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","description":"Simple scalar value in query."}
-          },
-          {
-            "name":"identity","in":"query","description":"JSON value in query",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryAdvancedJSONPayload"}}}
-          },
-          {
-            "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
-            "schema":{"type":"string","description":"Simple scalar value in path"}
-          },
-          {
-            "name":"in_cookie","in":"cookie","description":"UUID in cookie.",
-            "schema":{"$ref":"#/components/schemas/CookieUuidUUID"}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputWithJSON"}}}
-          }
-        },
-        "x-forbid-unknown-cookie":true,"x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/json-slice-body":{
-      "post":{
-        "tags":["Request"],"summary":"Request With JSON Array In Body",
-        "operationId":"_examples/advanced-generic.jsonSliceBody",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Simple scalar value in query.",
-            "schema":{"type":"integer","description":"Simple scalar value in query."}
-          },
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value in header.",
-            "schema":{"type":"string","description":"Simple scalar value in header."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJsonSliceReq"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJsonOutput"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/no-validation":{
-      "post":{
-        "tags":["Request","Response"],"summary":"No Validation","description":"Input/Output without validation.",
-        "operationId":"_examples/advanced-generic.noValidation",
-        "parameters":[
-          {"name":"q","in":"query","schema":{"type":"boolean"}},
-          {"name":"X-Input","in":"header","schema":{"type":"integer"}}
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInputPortType3"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "headers":{
-              "X-Output":{"style":"simple","schema":{"type":"integer"}},
-              "X-Query":{"style":"simple","schema":{"type":"boolean"}}
-            },
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputPortType3"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/output-csv-writer":{
-      "get":{
-        "tags":["Response"],"summary":"Output With Stream Writer","description":"Output with stream writer.",
-        "operationId":"_examples/advanced-generic.outputCSVWriter",
-        "parameters":[
-          {
-            "name":"If-None-Match","in":"header","description":"Content hash.",
-            "schema":{"type":"string","description":"Content hash."}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK",
-            "headers":{
-              "ETag":{
-                "style":"simple","description":"Content hash.","schema":{"type":"string","description":"Content hash."}
-              },
-              "X-Header":{
-                "style":"simple","description":"Sample response header.",
-                "schema":{"type":"string","description":"Sample response header."}
-              }
-            },
-            "content":{"text/csv":{"schema":{"type":"string"}}}
-          },
-          "304":{"description":"Not Modified"},
-          "500":{
-            "description":"Internal Server Error",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedCustomErr"}}}
-          }
-        }
-      }
-    },
-    "/output-headers":{
-      "get":{
-        "tags":["Response"],"summary":"Output With Headers","description":"Output with headers.",
-        "operationId":"_examples/advanced-generic.outputHeaders",
-        "parameters":[
-          {
-            "name":"X-foO","in":"header","description":"Reduced by 20 in response.","required":true,
-            "schema":{"minimum":10,"type":"integer","description":"Reduced by 20 in response."}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK",
-            "headers":{
-              "X-foO":{
-                "style":"simple","description":"Reduced by 20 in response.","required":true,
-                "schema":{"minimum":10,"type":"integer","description":"Reduced by 20 in response."}
-              },
-              "x-HeAdEr":{
-                "style":"simple","description":"Sample response header.",
-                "schema":{"type":"string","description":"Sample response header."}
-              },
-              "x-omit-empty":{
-                "style":"simple","description":"Receives req value of X-Foo reduced by 30.",
-                "schema":{"type":"integer","description":"Receives req value of X-Foo reduced by 30."}
-              }
-            },
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedHeaderOutput"}}}
-          },
-          "500":{
-            "description":"Internal Server Error",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedCustomErr"}}}
-          }
-        }
-      },
-      "head":{
-        "tags":["Response"],"summary":"Output With Headers","description":"Output with headers.",
-        "operationId":"_examples/advanced-generic.outputHeaders2",
-        "parameters":[
-          {
-            "name":"X-foO","in":"header","description":"Reduced by 20 in response.","required":true,
-            "schema":{"minimum":10,"type":"integer","description":"Reduced by 20 in response."}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK",
-            "headers":{
-              "X-foO":{
-                "style":"simple","description":"Reduced by 20 in response.","required":true,
-                "schema":{"minimum":10,"type":"integer","description":"Reduced by 20 in response."}
-              },
-              "x-HeAdEr":{
-                "style":"simple","description":"Sample response header.",
-                "schema":{"type":"string","description":"Sample response header."}
-              },
-              "x-omit-empty":{
-                "style":"simple","description":"Receives req value of X-Foo reduced by 30.",
-                "schema":{"type":"integer","description":"Receives req value of X-Foo reduced by 30."}
-              }
-            }
-          },
-          "500":{"description":"Internal Server Error"}
-        }
-      }
-    },
-    "/query-object":{
-      "get":{
-        "tags":["Request"],"summary":"Request With Object As Query Parameter",
-        "operationId":"_examples/advanced-generic.queryObject",
-        "parameters":[
-          {
-            "name":"in_query","in":"query","description":"Object value in query.","style":"deepObject","explode":true,
-            "schema":{"type":"object","additionalProperties":{"type":"number"},"description":"Object value in query."}
-          },
-          {
-            "name":"json_filter","in":"query","description":"JSON object value in query.",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryAdvancedJsonFilter"}}}
-          },
-          {
-            "name":"deep_object_filter","in":"query","description":"Deep object value in query params.",
-            "style":"deepObject","explode":true,"schema":{"$ref":"#/components/schemas/QueryAdvancedDeepObjectFilter"}
-          }
-        ],
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputQueryObject"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    },
-    "/req-resp-mapping":{
-      "post":{
-        "tags":["Request","Response"],"summary":"Request Response Mapping",
-        "description":"This use case has transport concerns fully decoupled with external req/resp mapping.",
-        "operationId":"reqRespMapping",
-        "parameters":[
-          {
-            "name":"X-Header","in":"header","description":"Simple scalar value with sample validation.","required":true,
-            "schema":{"minLength":3,"type":"string","description":"Simple scalar value with sample validation."}
-          }
-        ],
-        "requestBody":{
-          "content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/FormDataAdvancedInputPort"}}}
-        },
-        "responses":{
-          "204":{
-            "description":"No Content",
-            "headers":{
-              "X-Value-1":{
-                "style":"simple","description":"Simple scalar value with sample validation.","required":true,
-                "schema":{"minLength":3,"type":"string","description":"Simple scalar value with sample validation."}
-              },
-              "X-Value-2":{
-                "style":"simple","description":"Simple scalar value with sample validation.","required":true,
-                "schema":{"minimum":3,"type":"integer","description":"Simple scalar value with sample validation."}
-              }
-            }
-          }
-        }
-      }
-    },
-    "/root-with-session":{
-      "get":{
-        "tags":["Other"],"summary":"Dummy","operationId":"_examples/advanced-generic.dummy",
-        "responses":{
-          "204":{"description":"No Content"},
-          "401":{
-            "description":"Unauthorized",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestErrResponse"}}}
-          }
-        },
-        "security":[{"User":[]}]
-      }
-    },
-    "/text-req-body-ptr/{path}":{
-      "post":{
-        "tags":["Request"],"summary":"Request With Text Body (ptr input)",
-        "description":"This usecase allows direct access to original `*http.Request` while keeping automated decoding of parameters.",
-        "operationId":"_examples/advanced-generic.textReqBodyPtr",
-        "parameters":[
-          {"name":"query","in":"query","schema":{"type":"integer"}},
-          {"name":"path","in":"path","required":true,"schema":{"type":"string"}}
-        ],
-        "requestBody":{"content":{"text/csv":{"schema":{"type":"string"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputType3"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/text-req-body/{path}":{
-      "post":{
-        "tags":["Request"],"summary":"Request With Text Body",
-        "description":"This usecase allows direct access to original `*http.Request` while keeping automated decoding of parameters.",
-        "operationId":"_examples/advanced-generic.textReqBody",
-        "parameters":[
-          {"name":"query","in":"query","schema":{"type":"integer"}},
-          {"name":"path","in":"path","required":true,"schema":{"type":"string"}}
-        ],
-        "requestBody":{"content":{"text/csv":{"schema":{"type":"string"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputType2"}}}
-          }
-        },
-        "x-forbid-unknown-path":true,"x-forbid-unknown-query":true
-      }
-    },
-    "/validation":{
-      "post":{
-        "tags":["Request","Response","Validation"],"summary":"Validation",
-        "description":"Input/Output with validation. Custom annotation.",
-        "operationId":"_examples/advanced-generic.validation",
-        "parameters":[
-          {
-            "name":"q","in":"query",
-            "description":"This parameter will bypass explicit validation as it does not have constraints.",
-            "schema":{
-              "type":"boolean",
-              "description":"This parameter will bypass explicit validation as it does not have constraints."
-            }
-          },
-          {
-            "name":"X-Input","in":"header","description":"Request minimum: 10, response maximum: 20.",
-            "schema":{"minimum":10,"type":"integer","description":"Request minimum: 10, response maximum: 20."}
-          }
-        ],
-        "requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedInputPortType2"}}}},
-        "responses":{
-          "200":{
-            "description":"OK",
-            "headers":{
-              "X-Output":{"style":"simple","schema":{"maximum":20,"type":"integer"}},
-              "X-Query":{
-                "style":"simple","description":"This header bypasses validation as it does not have constraints.",
-                "schema":{"type":"boolean","description":"This header bypasses validation as it does not have constraints."}
-              }
-            },
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedOutputPortType2"}}}
-          }
-        },
-        "x-forbid-unknown-query":true
-      }
-    }
-  },
-  "components":{
-    "schemas":{
-      "AdvancedAnotherErr":{"type":"object","properties":{"foo":{"type":"integer"}}},
-      "AdvancedCustomErr":{"type":"object","properties":{"details":{"type":"object","additionalProperties":{}},"msg":{"type":"string"}}},
-      "AdvancedDeepObjectFilter":{
-        "type":"object",
-        "properties":{"bar":{"minLength":3,"type":"string"},"baz":{"minLength":3,"type":"string","nullable":true}}
-      },
-      "AdvancedGzipPassThroughStruct":{
-        "type":"object",
-        "properties":{"id":{"type":"integer"},"text":{"type":"array","items":{"type":"string"},"nullable":true}}
-      },
-      "AdvancedHeaderOutput":{"type":"object","properties":{"inBody":{"type":"string","deprecated":true}}},
-      "AdvancedInfo":{
-        "type":"object",
-        "properties":{
-          "filename":{"type":"string"},"header":{"$ref":"#/components/schemas/TextprotoMIMEHeader"},
-          "inQuery":{"type":"integer"},"peek1":{"type":"string"},"peek2":{"type":"string"},"simple":{"type":"string"},
-          "size":{"type":"integer"}
-        }
-      },
-      "AdvancedInfoType2":{
-        "type":"object",
-        "properties":{
-          "filenames":{"type":"array","items":{"type":"string"},"nullable":true},
-          "headers":{"type":"array","items":{"$ref":"#/components/schemas/TextprotoMIMEHeader"},"nullable":true},
-          "inQuery":{"type":"integer"},"peeks1":{"type":"array","items":{"type":"string"},"nullable":true},
-          "peeks2":{"type":"array","items":{"type":"string"},"nullable":true},"simple":{"type":"string"},
-          "sizes":{"type":"array","items":{"type":"integer"},"nullable":true}
-        }
-      },
-      "AdvancedInputPortType2":{
-        "required":["data"],"type":"object",
-        "properties":{
-          "data":{
-            "type":"object",
-            "properties":{"value":{"minLength":3,"type":"string","description":"Request minLength: 3, response maxLength: 7"}},
-            "additionalProperties":false
-          }
-        },
-        "additionalProperties":false
-      },
-      "AdvancedInputPortType3":{
-        "type":"object",
-        "properties":{"data":{"type":"object","properties":{"value":{"type":"string"}},"additionalProperties":false}},
-        "additionalProperties":false
-      },
-      "AdvancedInputWithJSONType2":{
-        "type":"object",
-        "properties":{
-          "id":{"type":"integer"},"name":{"type":"string"},
-          "namedStruct":{"allOf":[{"deprecated":true},{"$ref":"#/components/schemas/AdvancedJSONPayloadType2"}]}
-        },
-        "additionalProperties":false
-      },
-      "AdvancedInputWithJSONType3":{
-        "type":"object",
-        "properties":{
-          "id":{"type":"integer"},"name":{"type":"string"},
-          "namedStruct":{"allOf":[{"deprecated":true},{"$ref":"#/components/schemas/AdvancedJSONPayloadType3"}]}
-        },
-        "additionalProperties":false
-      },
-      "AdvancedInputWithJSONType4":{
-        "type":"object","properties":{"id":{"minimum":100,"type":"integer"},"name":{"minLength":3,"type":"string"}},
-        "additionalProperties":false
-      },
-      "AdvancedJSONMapPayload":{"type":"object","additionalProperties":{"type":"number"}},
-      "AdvancedJSONPayloadType2":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
-      "AdvancedJSONPayloadType3":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
-      "AdvancedJSONSlicePayload":{"type":"array","items":{"type":"integer"},"nullable":true},
-      "AdvancedJsonFilter":{"type":"object","properties":{"foo":{"maxLength":5,"type":"string"}}},
-      "AdvancedJsonMapReq":{"type":"object","additionalProperties":{"type":"number"}},
-      "AdvancedJsonOutput":{
-        "type":"object",
-        "properties":{
-          "data":{"$ref":"#/components/schemas/AdvancedJSONSlicePayload"},"inHeader":{"type":"string"},
-          "inQuery":{"type":"integer"}
-        }
-      },
-      "AdvancedJsonOutputType2":{
-        "type":"object",
-        "properties":{
-          "data":{"$ref":"#/components/schemas/AdvancedJSONMapPayload"},"inHeader":{"type":"string"},
-          "inQuery":{"type":"integer"}
-        }
-      },
-      "AdvancedJsonSliceReq":{"type":"array","items":{"type":"integer"}},
-      "AdvancedOkResp":{"type":"object","properties":{"status":{"type":"string"}}},
-      "AdvancedOutput":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}},
-      "AdvancedOutputPortType2":{
-        "required":["data"],"type":"object",
-        "properties":{"data":{"type":"object","properties":{"value":{"maxLength":7,"type":"string"}}}}
-      },
-      "AdvancedOutputPortType3":{"type":"object","properties":{"data":{"type":"object","properties":{"value":{"type":"string"}}}}},
-      "AdvancedOutputQueryObject":{
-        "type":"object",
-        "properties":{
-          "deepObjectFilter":{"$ref":"#/components/schemas/AdvancedDeepObjectFilter"},
-          "inQuery":{"type":"object","additionalProperties":{"type":"number"},"nullable":true},
-          "jsonFilter":{"$ref":"#/components/schemas/AdvancedJsonFilter"}
-        }
-      },
-      "AdvancedOutputType2":{"type":"object","properties":{"path":{"type":"string"},"query":{"type":"integer"},"text":{"type":"string"}}},
-      "AdvancedOutputType3":{"type":"object","properties":{"path":{"type":"string"},"query":{"type":"integer"},"text":{"type":"string"}}},
-      "AdvancedOutputWithJSON":{
-        "type":"object",
-        "properties":{
-          "id":{"type":"integer"},"inHeader":{"type":"string"},"inPath":{"type":"string"},"inQuery":{"type":"integer"},
-          "name":{"type":"string"}
-        }
-      },
-      "AdvancedOutputWithJSONType2":{
-        "type":"object",
-        "properties":{
-          "id":{"type":"integer"},"inHeader":{"type":"string"},"inPath":{"type":"string"},
-          "inQuery":{"type":"string","format":"date","deprecated":true},"name":{"type":"string"}
-        }
-      },
-      "AdvancedOutputWithJSONType3":{
-        "type":"object",
-        "properties":{
-          "id":{"type":"integer"},"inHeader":{"type":"string"},"inPath":{"type":"string"},
-          "inQuery":{"type":"string","format":"date","deprecated":true},"name":{"type":"string"}
-        }
-      },
-      "AdvancedOutputWithJSONType4":{
-        "type":"object",
-        "properties":{
-          "id":{"minimum":100,"type":"integer"},"inHeader":{"minLength":3,"type":"string"},
-          "inPath":{"minLength":3,"type":"string"},"inQuery":{"minimum":3,"type":"integer"},
-          "name":{"minLength":3,"type":"string"}
-        }
-      },
-      "CookieUuidUUID":{"type":"string","format":"uuid","example":"248df4b7-aa70-47b8-a036-33ac447e668d"},
-      "FormDataAdvancedForm":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
-      "FormDataAdvancedInputPort":{
-        "required":["val2"],"type":"object",
-        "properties":{"val2":{"minimum":3,"type":"integer","description":"Simple scalar value with sample validation."}},
-        "additionalProperties":false
-      },
-      "FormDataAdvancedUpload":{
-        "type":"object",
-        "properties":{
-          "simple":{"type":"string","description":"Simple scalar value in body."},
-          "upload1":{"$ref":"#/components/schemas/FormDataMultipartFileHeader"},
-          "upload2":{"$ref":"#/components/schemas/FormDataMultipartFile"}
-        },
-        "additionalProperties":false
-      },
-      "FormDataAdvancedUploadType2":{
-        "type":"object",
-        "properties":{
-          "simple":{"type":"string","description":"Simple scalar value in body."},
-          "uploads1":{
-            "type":"array","items":{"$ref":"#/components/schemas/FormDataMultipartFileHeader"},
-            "description":"Uploads with *multipart.FileHeader.","nullable":true
-          },
-          "uploads2":{
-            "type":"array","items":{"$ref":"#/components/schemas/FormDataMultipartFile"},
-            "description":"Uploads with multipart.File.","nullable":true
-          }
-        },
-        "additionalProperties":false
-      },
-      "FormDataMultipartFile":{"type":"string","format":"binary","nullable":true},
-      "FormDataMultipartFileHeader":{"type":"string","format":"binary","nullable":true},
-      "QueryAdvancedDeepObjectFilter":{
-        "type":"object",
-        "properties":{"bar":{"minLength":3,"type":"string"},"baz":{"minLength":3,"type":"string","nullable":true}},
-        "additionalProperties":false
-      },
-      "QueryAdvancedJSONPayload":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
-      "QueryAdvancedJsonFilter":{"type":"object","properties":{"foo":{"maxLength":5,"type":"string"}},"additionalProperties":false},
-      "RestErrResponse":{
-        "type":"object",
-        "properties":{
-          "code":{"type":"integer","description":"Application-specific error code."},
-          "context":{"type":"object","additionalProperties":{},"description":"Application context."},
-          "error":{"type":"string","description":"Error message."},
-          "status":{"type":"string","description":"Status text."}
-        }
-      },
-      "TextprotoMIMEHeader":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}
-    },
-    "securitySchemes":{"User":{"type":"apiKey","name":"sessid","in":"cookie","description":"Session cookie."}}
-  }
-}
diff --git a/_examples/advanced-generic/gzip_pass_through_test.go b/_examples/advanced-generic/gzip_pass_through_test.go
deleted file mode 100644
index c50bb04..0000000
--- a/_examples/advanced-generic/gzip_pass_through_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/valyala/fasthttp"
-)
-
-func Test_directGzip(t *testing.T) {
-	r := NewRouter()
-
-	req, err := http.NewRequest(http.MethodGet, "/gzip-pass-through", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("Accept-Encoding", "gzip")
-
-	rw := httptest.NewRecorder()
-
-	r.ServeHTTP(rw, req)
-	assert.Equal(t, http.StatusOK, rw.Code)
-	assert.Equal(t, "330epditz19z", rw.Header().Get("Etag"))
-	assert.Equal(t, "gzip", rw.Header().Get("Content-Encoding"))
-	assert.Equal(t, "abc", rw.Header().Get("X-Header"))
-	assert.Less(t, len(rw.Body.Bytes()), 500)
-}
-
-func Test_noDirectGzip(t *testing.T) {
-	r := NewRouter()
-
-	req, err := http.NewRequest(http.MethodGet, "/gzip-pass-through?plainStruct=1", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("Accept-Encoding", "gzip")
-
-	rw := httptest.NewRecorder()
-
-	r.ServeHTTP(rw, req)
-	assert.Equal(t, http.StatusOK, rw.Code)
-	assert.Equal(t, "", rw.Header().Get("Etag")) // No ETag for dynamic compression.
-	assert.Equal(t, "gzip", rw.Header().Get("Content-Encoding"))
-	assert.Equal(t, "cba", rw.Header().Get("X-Header"))
-	assert.Less(t, len(rw.Body.Bytes()), 1000) // Worse compression for better speed.
-}
-
-func Test_directGzip_perf(t *testing.T) {
-	res := testing.Benchmark(Benchmark_directGzip)
-
-	if httptestbench.RaceDetectorEnabled {
-		assert.Less(t, res.Extra["B:rcvd/op"], 700.0)
-		assert.Less(t, res.Extra["B:sent/op"], 104.0)
-		assert.Less(t, res.AllocsPerOp(), int64(60))
-		assert.Less(t, res.AllocedBytesPerOp(), int64(8500))
-	} else {
-		assert.Less(t, res.Extra["B:rcvd/op"], 700.0)
-		assert.Less(t, res.Extra["B:sent/op"], 104.0)
-		assert.Less(t, res.AllocsPerOp(), int64(45))
-		assert.Less(t, res.AllocedBytesPerOp(), int64(4100))
-	}
-}
-
-// Direct gzip enabled.
-// Benchmark_directGzip-4   	   48037	     24474 ns/op	       624 B:rcvd/op	       103 B:sent/op	     40860 rps	    3499 B/op	      36 allocs/op.
-// Benchmark_directGzip-4   	   45792	     26102 ns/op	       624 B:rcvd/op	       103 B:sent/op	     38278 rps	    3063 B/op	      33 allocs/op.
-func Benchmark_directGzip(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.Set("Accept-Encoding", "gzip")
-		req.SetRequestURI(srv.URL + "/gzip-pass-through")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-// Direct gzip enabled.
-// Benchmark_directGzipHead-4   	   43804	     26481 ns/op	       168 B:rcvd/op	       104 B:sent/op	     37730 rps	    3507 B/op	      36 allocs/op.
-// Benchmark_directGzipHead-4   	   45580	     32286 ns/op	       168 B:rcvd/op	       104 B:sent/op	     30963 rps	    3093 B/op	      33 allocs/op.
-func Benchmark_directGzipHead(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodHead)
-		req.Header.Set("Accept-Encoding", "gzip")
-		req.SetRequestURI(srv.URL + "/gzip-pass-through")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-// Direct gzip disabled, payload is marshaled and compressed for every request.
-// Benchmark_noDirectGzip-4   	    8031	    136836 ns/op	      1029 B:rcvd/op	       117 B:sent/op	      7308 rps	    5382 B/op	      41 allocs/op.
-// Benchmark_noDirectGzip-4   	    7587	    143294 ns/op	      1029 B:rcvd/op	       117 B:sent/op	      6974 rps	    4619 B/op	      38 allocs/op.
-// Benchmark_noDirectGzip-4   	    7825	    157317 ns/op	      1029 B:rcvd/op	       117 B:sent/op	      6357 rps	    4655 B/op	      40 allocs/op.
-func Benchmark_noDirectGzip(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.Set("Accept-Encoding", "gzip")
-		req.SetRequestURI(srv.URL + "/gzip-pass-through?plainStruct=1")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-// Direct gzip enabled, payload is unmarshaled and decompressed for every request in usecase body.
-// Unmarshaling large JSON payloads can be much more expensive than explicitly creating them from Go values.
-// Benchmark_directGzip_decode-4   	    2018	    499755 ns/op	       624 B:rcvd/op	       116 B:sent/op	      2001 rps	  403967 B/op	     496 allocs/op.
-// Benchmark_directGzip_decode-4   	    2085	    526586 ns/op	       624 B:rcvd/op	       116 B:sent/op	      1899 rps	  403600 B/op	     493 allocs/op.
-func Benchmark_directGzip_decode(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.Set("Accept-Encoding", "gzip")
-		req.SetRequestURI(srv.URL + "/gzip-pass-through?countItems=1")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-// Direct gzip disabled.
-// Benchmark_noDirectGzip_decode-4   	    7603	    142173 ns/op	      1029 B:rcvd/op	       130 B:sent/op	      7034 rps	    5122 B/op	      43 allocs/op.
-// Benchmark_noDirectGzip_decode-4   	    5836	    198000 ns/op	      1029 B:rcvd/op	       130 B:sent/op	      5051 rps	    5371 B/op	      42 allocs/op.
-func Benchmark_noDirectGzip_decode(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.Set("Accept-Encoding", "gzip")
-		req.SetRequestURI(srv.URL + "/gzip-pass-through?plainStruct=1&countItems=1")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
diff --git a/_examples/advanced-generic/html_response_test.go b/_examples/advanced-generic/html_response_test.go
deleted file mode 100644
index dd65ebe..0000000
--- a/_examples/advanced-generic/html_response_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package main
-
-import (
-	"io"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/valyala/fasthttp"
-)
-
-func Test_htmlResponse(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	resp, err := http.Get(srv.URL + "/html-response/123?filter=feel")
-	require.NoError(t, err)
-
-	assert.Equal(t, resp.StatusCode, http.StatusOK)
-
-	body, err := io.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-
-	assert.Equal(t, "true", resp.Header.Get("X-Anti-Header"))
-	assert.Equal(t, "text/html", resp.Header.Get("Content-Type"))
-	assert.Equal(t, `<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="UTF-8">
-		<title>Foo</title>
-	</head>
-	<body>
-		<a href="/html-response/124?filter=feel">Next Foo</a><br />
-		<div>foo</div><div>bar</div><div>baz</div>
-	</body>
-</html>`, string(body), string(body))
-}
-
-// Benchmark_htmlResponse-12    	   89209	     12348 ns/op	         0.3801 50%:ms	         1.119 90%:ms	         2.553 99%:ms	         3.877 99.9%:ms	       370.0 B:rcvd/op	       108.0 B:sent/op	     80973 rps	    8279 B/op	     144 allocs/op.
-func Benchmark_htmlResponse(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.SetRequestURI(srv.URL + "/html-response/123?filter=feel")
-		req.Header.Set("X-Header", "true")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
diff --git a/_examples/advanced-generic/json_body_manual_test.go b/_examples/advanced-generic/json_body_manual_test.go
deleted file mode 100644
index 96f952f..0000000
--- a/_examples/advanced-generic/json_body_manual_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/valyala/fasthttp"
-)
-
-// Benchmark_jsonBodyManual-12    	  125672	      8542 ns/op	       208.0 B:rcvd/op	       195.0 B:sent/op	    117048 rps	    4523 B/op	      49 allocs/op.
-func Benchmark_jsonBodyManual(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/json-body-manual/abc?in_query=2006-01-02")
-		req.Header.Set("Content-Type", "application/json")
-		req.Header.Set("X-Header", "def")
-		req.SetBody([]byte(`{"id":321,"name":"Jane"}`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusCreated
-	})
-}
diff --git a/_examples/advanced-generic/json_body_test.go b/_examples/advanced-generic/json_body_test.go
deleted file mode 100644
index 55e9f0b..0000000
--- a/_examples/advanced-generic/json_body_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/valyala/fasthttp"
-)
-
-// Benchmark_jsonBody-12    	   96762	     12042 ns/op	       208.0 B:rcvd/op	       188.0 B:sent/op	     83033 rps	   10312 B/op	     100 allocs/op.
-func Benchmark_jsonBody(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/json-body/abc?in_query=2006-01-02")
-		req.Header.Set("Content-Type", "application/json")
-		req.Header.Set("X-Header", "def")
-		req.SetBody([]byte(`{"id":321,"name":"Jane"}`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusCreated
-	})
-}
diff --git a/_examples/advanced-generic/json_body_validation_test.go b/_examples/advanced-generic/json_body_validation_test.go
deleted file mode 100644
index 69e7548..0000000
--- a/_examples/advanced-generic/json_body_validation_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/valyala/fasthttp"
-)
-
-// Benchmark_jsonBodyValidation-4   	   19126	     60170 ns/op	       194 B:rcvd/op	       192 B:sent/op	     16620 rps	   18363 B/op	     144 allocs/op.
-func Benchmark_jsonBodyValidation(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/json-body-validation/abc?in_query=123")
-		req.Header.Set("Content-Type", "application/json")
-		req.Header.Set("X-Header", "def")
-		req.SetBody([]byte(`{"id":321,"name":"Jane"}`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
diff --git a/_examples/advanced-generic/output_headers_test.go b/_examples/advanced-generic/output_headers_test.go
deleted file mode 100644
index 929135f..0000000
--- a/_examples/advanced-generic/output_headers_test.go
+++ /dev/null
@@ -1,136 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"io"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/swaggest/assertjson"
-	"github.com/valyala/fasthttp"
-)
-
-// Benchmark_outputHeaders-4   	   41424	     27054 ns/op	       154 B:rcvd/op	        77.0 B:sent/op	     36963 rps	    3641 B/op	      35 allocs/op.
-func Benchmark_outputHeaders(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodGet)
-		req.SetRequestURI(srv.URL + "/output-headers")
-		req.Header.Set("X-Foo", "40")
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-func Test_outputHeaders(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	req, err := http.NewRequest(http.MethodGet, srv.URL+"/output-headers", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("x-FoO", "40")
-
-	resp, err := http.DefaultTransport.RoundTrip(req)
-	require.NoError(t, err)
-
-	assert.Equal(t, resp.StatusCode, http.StatusOK)
-
-	body, err := io.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-
-	assert.Equal(t, "abc", resp.Header.Get("X-Header"))
-	assert.Equal(t, "20", resp.Header.Get("X-Foo"))
-	assert.Equal(t, "10", resp.Header.Get("X-Omit-Empty"))
-	assert.Equal(t, []string{"coo=123; HttpOnly"}, resp.Header.Values("Set-Cookie"))
-	assertjson.Equal(t, []byte(`{"inBody":"def"}`), body)
-}
-
-func Test_outputHeaders_invalidReq(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	req, err := http.NewRequest(http.MethodGet, srv.URL+"/output-headers", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("x-FoO", "5")
-
-	resp, err := http.DefaultTransport.RoundTrip(req)
-	require.NoError(t, err)
-
-	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
-
-	body, err := io.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-
-	assertjson.Equal(t,
-		[]byte(`{"msg":"invalid argument: validation failed","details":{"header:X-Foo":["#: must be >= 10/1 but found 5"]}}`),
-		body, string(body))
-}
-
-func Test_outputHeaders_invalidResp(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	req, err := http.NewRequest(http.MethodGet, srv.URL+"/output-headers", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("x-FoO", "15")
-
-	resp, err := http.DefaultTransport.RoundTrip(req)
-	require.NoError(t, err)
-
-	assert.Equal(t, resp.StatusCode, http.StatusInternalServerError)
-
-	body, err := io.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-
-	assertjson.Equal(t,
-		[]byte(`{"msg":"internal: bad response: validation failed","details":{"header:X-Foo":["#: must be >= 10/1 but found -5"]}}`),
-		body, string(body))
-}
-
-func Test_outputHeaders_omitempty(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	req, err := http.NewRequest(http.MethodGet, srv.URL+"/output-headers", nil)
-	require.NoError(t, err)
-
-	req.Header.Set("x-FoO", "30")
-
-	resp, err := http.DefaultTransport.RoundTrip(req)
-	require.NoError(t, err)
-
-	assert.Equal(t, resp.StatusCode, http.StatusOK)
-
-	body, err := io.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-
-	assert.Equal(t, "abc", resp.Header.Get("X-Header"))
-	assert.Equal(t, "10", resp.Header.Get("X-Foo"))
-	assert.Equal(t, []string(nil), resp.Header.Values("X-Omit-Empty"))
-	assert.Equal(t, []string{"coo=123; HttpOnly"}, resp.Header.Values("Set-Cookie"))
-	assertjson.Equal(t, []byte(`{"inBody":"def"}`), body)
-}
diff --git a/_examples/advanced-generic/query_object_test.go b/_examples/advanced-generic/query_object_test.go
deleted file mode 100644
index cf95747..0000000
--- a/_examples/advanced-generic/query_object_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"io"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/swaggest/assertjson"
-)
-
-func Test_queryObject(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	for _, tc := range []struct {
-		name string
-		url  string
-		code int
-		resp string
-	}{
-		{
-			name: "validation_failed_deep_object",
-			url:  `/query-object?in_query[1]=0&in_query[2]=0&in_query[3]=0&json_filter={"foo":"strin"}&deep_object_filter[bar]=sd`,
-			code: http.StatusBadRequest,
-			resp: `{
-			  "msg":"invalid argument: validation failed",
-			  "details":{"query:deep_object_filter":["#/bar: length must be \u003e= 3, but got 2"]}
-			}`,
-		},
-		{
-			name: "validation_failed_deep_object_2",
-			url:  `/query-object?in_query[1]=0&in_query[2]=0&in_query[3]=0&json_filter={"foo":"strin"}&deep_object_filter[bar]=asd&deep_object_filter[baz]=sd`,
-			code: http.StatusBadRequest,
-			resp: `{
-			  "msg":"invalid argument: validation failed",
-			  "details":{"query:deep_object_filter":["#/baz: length must be \u003e= 3, but got 2"]}
-			}`,
-		},
-		{
-			name: "validation_failed_json",
-			url:  `/query-object?in_query[1]=0&in_query[2]=0&in_query[3]=0&json_filter={"foo":"string"}&deep_object_filter[bar]=asd`,
-			code: http.StatusBadRequest,
-			resp: `{
-			  "msg":"invalid argument: validation failed",
-			  "details":{"query:json_filter":["#/foo: length must be \u003c= 5, but got 6"]}
-			}`,
-		},
-		{
-			name: "ok",
-			url:  `/query-object?in_query[1]=0&in_query[2]=0&in_query[3]=0&json_filter={"foo":"strin"}&deep_object_filter[bar]=asd`,
-			code: http.StatusOK,
-			resp: `{
-			  "inQuery":{"1":0,"2":0,"3":0},"jsonFilter":{"foo":"strin"},
-			  "deepObjectFilter":{"bar":"asd"}
-			}`,
-		},
-	} {
-		t.Run(tc.name, func(t *testing.T) {
-			req, err := http.NewRequest(
-				http.MethodGet,
-				srv.URL+tc.url,
-				nil,
-			)
-			require.NoError(t, err)
-
-			resp, err := http.DefaultTransport.RoundTrip(req)
-			require.NoError(t, err)
-
-			body, err := io.ReadAll(resp.Body)
-			assert.NoError(t, err)
-			assert.NoError(t, resp.Body.Close())
-			assertjson.EqMarshal(t, tc.resp, json.RawMessage(body))
-			assert.Equal(t, tc.code, resp.StatusCode)
-		})
-	}
-}
diff --git a/_examples/advanced-generic/request_response_mapping_test.go b/_examples/advanced-generic/request_response_mapping_test.go
deleted file mode 100644
index 0c85192..0000000
--- a/_examples/advanced-generic/request_response_mapping_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"bytes"
-	"io/ioutil"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/valyala/fasthttp"
-)
-
-func Test_requestResponseMapping(t *testing.T) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	req, err := http.NewRequest(http.MethodPost, srv.URL+"/req-resp-mapping",
-		bytes.NewReader([]byte(`val2=3`)))
-	require.NoError(t, err)
-	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-	req.Header.Set("X-Header", "abc")
-
-	resp, err := http.DefaultTransport.RoundTrip(req)
-	require.NoError(t, err)
-
-	assert.Equal(t, http.StatusNoContent, resp.StatusCode)
-
-	body, err := ioutil.ReadAll(resp.Body)
-	assert.NoError(t, err)
-	assert.NoError(t, resp.Body.Close())
-	assert.Equal(t, "", string(body))
-
-	assert.Equal(t, "abc", resp.Header.Get("X-Value-1"))
-	assert.Equal(t, "3", resp.Header.Get("X-Value-2"))
-}
-
-func Benchmark_requestResponseMapping(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/req-resp-mapping")
-		req.Header.Set("X-Header", "abc")
-		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-		req.SetBody([]byte(`val2=3`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusNoContent
-	})
-}
diff --git a/_examples/advanced-generic/router_test.go b/_examples/advanced-generic/router_test.go
deleted file mode 100644
index a581145..0000000
--- a/_examples/advanced-generic/router_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-	"net/http/httptest"
-	"os"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"github.com/swaggest/assertjson"
-)
-
-func TestNewRouter(t *testing.T) {
-	r := NewRouter()
-
-	req, err := http.NewRequest(http.MethodGet, "/docs/openapi.json", nil)
-	require.NoError(t, err)
-
-	rw := httptest.NewRecorder()
-
-	r.ServeHTTP(rw, req)
-	assert.Equal(t, http.StatusOK, rw.Code)
-
-	actualSchema, err := assertjson.MarshalIndentCompact(json.RawMessage(rw.Body.Bytes()), "", "  ", 120)
-	require.NoError(t, err)
-
-	expectedSchema, err := os.ReadFile("_testdata/openapi.json")
-	require.NoError(t, err)
-
-	if !assertjson.Equal(t, expectedSchema, rw.Body.Bytes(), string(actualSchema)) {
-		require.NoError(t, os.WriteFile("_testdata/openapi_last_run.json", actualSchema, 0o600))
-	}
-}
diff --git a/_examples/advanced-generic/validation_test.go b/_examples/advanced-generic/validation_test.go
deleted file mode 100644
index 227ea0f..0000000
--- a/_examples/advanced-generic/validation_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-//go:build go1.18
-
-package main
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/bool64/httptestbench"
-	"github.com/valyala/fasthttp"
-)
-
-// Benchmark_validation-4   	   18979	     53012 ns/op	       197 B:rcvd/op	       170 B:sent/op	     18861 rps	   14817 B/op	     131 allocs/op.
-// Benchmark_validation-4   	   17665	     58243 ns/op	       177 B:rcvd/op	       170 B:sent/op	     17161 rps	   16349 B/op	     132 allocs/op.
-func Benchmark_validation(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/validation?q=true")
-		req.Header.Set("X-Input", "12")
-		req.Header.Set("Content-Type", "application/json")
-		req.SetBody([]byte(`{"data":{"value":"abc"}}`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
-
-func Benchmark_noValidation(b *testing.B) {
-	r := NewRouter()
-
-	srv := httptest.NewServer(r)
-	defer srv.Close()
-
-	httptestbench.RoundTrip(b, 50, func(i int, req *fasthttp.Request) {
-		req.Header.SetMethod(http.MethodPost)
-		req.SetRequestURI(srv.URL + "/no-validation?q=true")
-		req.Header.Set("X-Input", "12")
-		req.Header.Set("Content-Type", "application/json")
-		req.SetBody([]byte(`{"data":{"value":"abc"}}`))
-	}, func(i int, resp *fasthttp.Response) bool {
-		return resp.StatusCode() == http.StatusOK
-	})
-}
diff --git a/_examples/advanced/_testdata/openapi.json b/_examples/advanced/_testdata/openapi.json
index 5bcc7e4..17b7961 100644
--- a/_examples/advanced/_testdata/openapi.json
+++ b/_examples/advanced/_testdata/openapi.json
@@ -237,7 +237,7 @@
           },
           {
             "name":"identity","in":"query","description":"JSON value in query",
-            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryAdvancedJSONPayload"}}}
+            "content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdvancedJSONPayload"}}}
           },
           {
             "name":"in-path","in":"path","description":"Simple scalar value in path","required":true,
@@ -245,7 +245,7 @@
           },
           {
             "name":"in_cookie","in":"cookie","description":"UUID in cookie.",
-            "schema":{"$ref":"#/components/schemas/CookieUuidUUID"}
+            "schema":{"$ref":"#/components/schemas/UuidUUID"}
           },
           {
             "name":"X-Header","in":"header","description":"Simple scalar value in header.",
@@ -512,6 +512,7 @@
         "additionalProperties":false
       },
       "AdvancedJSONMapPayload":{"type":"object","additionalProperties":{"type":"number"}},
+      "AdvancedJSONPayload":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
       "AdvancedJSONPayloadType2":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
       "AdvancedJSONSlicePayload":{"type":"array","items":{"type":"integer"},"nullable":true},
       "AdvancedJsonMapReq":{"type":"object","additionalProperties":{"type":"number"},"nullable":true},
@@ -562,7 +563,6 @@
           "name":{"minLength":3,"type":"string"}
         }
       },
-      "CookieUuidUUID":{"type":"string","format":"uuid","example":"248df4b7-aa70-47b8-a036-33ac447e668d"},
       "FormDataAdvancedInputPort":{
         "required":["val2"],"type":"object",
         "properties":{"val2":{"minimum":3,"type":"integer","description":"Simple scalar value with sample validation."}},
@@ -594,7 +594,6 @@
       },
       "FormDataMultipartFile":{"type":"string","format":"binary","nullable":true},
       "FormDataMultipartFileHeader":{"type":"string","format":"binary","nullable":true},
-      "QueryAdvancedJSONPayload":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"additionalProperties":false},
       "RestErrResponse":{
         "type":"object",
         "properties":{
@@ -604,7 +603,8 @@
           "status":{"type":"string","description":"Status text."}
         }
       },
-      "TextprotoMIMEHeader":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}
+      "TextprotoMIMEHeader":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},
+      "UuidUUID":{"type":"string","format":"uuid","example":"248df4b7-aa70-47b8-a036-33ac447e668d"}
     },
     "securitySchemes":{"User":{"type":"apiKey","name":"sessid","in":"cookie","description":"Session cookie."}}
   }
diff --git a/openapi/collector_test.go b/openapi/collector_test.go
index 2ea83f3..3a3cc86 100644
--- a/openapi/collector_test.go
+++ b/openapi/collector_test.go
@@ -443,16 +443,14 @@ func TestCollector_Collect_queryObject(t *testing.T) {
 				"name":"json_filter","in":"query",
 				"description":"JSON object value in query.",
 				"content":{
-				  "application/json":{
-					"schema":{"$ref":"#/components/schemas/QueryOpenapiTestJsonFilter"}
-				  }
+				  "application/json":{"schema":{"$ref":"#/components/schemas/OpenapiTestJsonFilter"}}
 				}
 			  },
 			  {
 				"name":"deep_object_filter","in":"query",
 				"description":"Deep object value in query params.",
 				"style":"deepObject","explode":true,
-				"schema":{"$ref":"#/components/schemas/QueryOpenapiTestDeepObjectFilter"}
+				"schema":{"$ref":"#/components/schemas/OpenapiTestDeepObjectFilter"}
 			  }
 			],
 			"responses":{"204":{"description":"No Content"}}
@@ -461,8 +459,8 @@ func TestCollector_Collect_queryObject(t *testing.T) {
 	  },
 	  "components":{
 		"schemas":{
-		  "QueryOpenapiTestDeepObjectFilter":{"type":"object","properties":{"bar":{"type":"string"}}},
-		  "QueryOpenapiTestJsonFilter":{"type":"object","properties":{"foo":{"type":"string"}}}
+		  "OpenapiTestDeepObjectFilter":{"type":"object","properties":{"bar":{"type":"string"}}},
+		  "OpenapiTestJsonFilter":{"type":"object","properties":{"foo":{"type":"string"}}}
 		}
 	  }
 	}`, c.SpecSchema())