Repository: swaggest/rest
Pull request #185 (2024-01-01 12:43:54)

Add methods for NotFound and MethodNotAllowed, add response.EmbeddedSetter

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

| Language | Files |   Lines    |    Code    | Comments |  Blanks   | Complexity |     Bytes      |
|----------|-------|------------|------------|----------|-----------|------------|----------------|
| Go       | 112   | 8531 (+22) | 6147 (+12) | 642 (+5) | 1742 (+5) | 1018 (+1)  | 207.8K (+864B) |
<!-- Sticky Pull Request CommentLOC -->
github-actions[bot]: ### Go API Changes

<pre>
# github.com/swaggest/rest/chirouter
## compatible changes
(*Wrapper).HandlerFunc: added

# github.com/swaggest/rest/web
## compatible changes
(*Service).OnMethodNotAllowed: added
(*Service).OnNotFound: added
github.com/swaggest/rest/chirouter.(*Wrapper).HandlerFunc: added

# summary
Inferred base version: v0.2.60
Suggested version: v0.3.0
</pre>
<!-- Sticky Pull Request Commentgorelease -->
github-actions[bot]: ### Unit Test Coverage
total:								(statements)			80.9%
changed lines: (statements) 42.9%, coverage is less than 90.0%, consider testing the changes more thoroughly
<details><summary>Coverage of changed lines</summary>

|           File           |      Function      | Coverage |
|--------------------------|--------------------|----------|
| Total                    |                    | 42.9%    |
| chirouter/wrapper.go     |                    | 0.0%     |
| chirouter/wrapper.go:205 | HandlerFunc        | 0.0%     |
| request/middleware.go    |                    | 100.0%   |
| request/middleware.go:20 | DecoderMiddleware  | 100.0%   |
| web/service.go           |                    | 0.0%     |
| web/service.go:166       | OnNotFound         | 0.0%     |
| web/service.go:171       | OnMethodNotAllowed | 0.0%     |

</details>

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

|         File          |      Function      | Base Coverage | Current Coverage |
|-----------------------|--------------------|---------------|------------------|
| Total                 |                    | 81.0%         | 80.9% (-0.1%)    |
| chirouter/wrapper.go  | HandlerFunc        | no function   | 0.0%             |
| request/middleware.go | DecoderMiddleware  | 93.3%         | 94.1% (+0.8%)    |
| web/service.go        | OnMethodNotAllowed | no function   | 0.0%             |
| web/service.go        | OnNotFound         | no function   | 0.0%             |

</details>
<!-- Sticky Pull Request Commentunit-test -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) Report
Attention: `4 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`d64d866`)](https://app.codecov.io/gh/swaggest/rest/commit/d64d8669ad3a166b90bde9aac1a60851021cfe6c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) 76.00% compared to head [(`4733545`)](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) 75.83%.

| [Files](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) | Patch % | Lines |
|---|---|---|
| [chirouter/wrapper.go](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest#diff-Y2hpcm91dGVyL3dyYXBwZXIuZ28=) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) |
| [web/service.go](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest#diff-d2ViL3NlcnZpY2UuZ28=) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #185      +/-   ##
==========================================
- Coverage   76.00%   75.83%   -0.17%     
==========================================
  Files          30       30              
  Lines        1700     1705       +5     
==========================================
+ Hits         1292     1293       +1     
- Misses        295      299       +4     
  Partials      113      113              
```

| [Flag](https://app.codecov.io/gh/swaggest/rest/pull/185/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/swaggest/rest/pull/185/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest) | `75.83% <42.85%> (-0.17%)` | :arrow_down: |

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.


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/swaggest/rest/pull/185?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=swaggest).

github-actions[bot]: ### Benchmark Result
<details><summary>Benchmark diff with base branch</summary>

```
Module github.com/bool64/dev not found, downloading.
name                                    old time/op    new time/op    delta
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4    1.10µs ± 0%    1.09µs ± 1%  -0.43%  (p=0.043 n=6+5)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                           511ns ± 0%     511ns ± 0%    ~     (p=0.139 n=6+5)
DecoderFunc_Decode-4                      1.49µs ± 1%    1.49µs ± 0%    ~     (p=0.749 n=5+6)
Decoder_Decode_json-4                     18.2µs ± 0%    18.2µs ± 1%    ~     (p=0.416 n=6+6)
Decoder_Decode_queryObject-4              3.91µs ± 0%    3.90µs ± 0%    ~     (p=0.255 n=6+6)
Decoder_Decode_jsonParam-4                1.51µs ± 0%    1.50µs ± 0%  -0.43%  (p=0.006 n=6+6)
DecoderFactory_SetDecoderFunc-4           1.31µs ± 1%    1.31µs ± 1%    ~     (p=0.307 n=6+6)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                              11.5µs ± 2%    11.4µs ± 0%    ~     (p=0.126 n=6+5)
Middleware_control-4                      2.59µs ± 0%    2.58µs ± 2%    ~     (p=0.236 n=6+6)

name                                    old alloc/op   new alloc/op   delta
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4    2.46kB ± 0%    2.46kB ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                            440B ± 0%      440B ± 0%    ~     (all equal)
DecoderFunc_Decode-4                      1.51kB ± 0%    1.51kB ± 0%    ~     (all equal)
Decoder_Decode_json-4                     12.2kB ± 0%    12.2kB ± 0%    ~     (all equal)
Decoder_Decode_queryObject-4              2.00kB ± 0%    2.00kB ± 0%    ~     (p=0.545 n=6+5)
Decoder_Decode_jsonParam-4                  736B ± 0%      736B ± 0%    ~     (all equal)
DecoderFactory_SetDecoderFunc-4           1.02kB ± 0%    1.02kB ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                              1.25kB ± 4%    1.25kB ± 5%    ~     (p=0.848 n=6+6)
Middleware_control-4                      11.2kB ± 0%    11.2kB ± 0%    ~     (all equal)

name                                    old allocs/op  new allocs/op  delta
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4      8.00 ± 0%      8.00 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                            4.00 ± 0%      4.00 ± 0%    ~     (all equal)
DecoderFunc_Decode-4                        12.0 ± 0%      12.0 ± 0%    ~     (all equal)
Decoder_Decode_json-4                        177 ± 0%       177 ± 0%    ~     (all equal)
Decoder_Decode_queryObject-4                36.0 ± 0%      36.0 ± 0%    ~     (all equal)
Decoder_Decode_jsonParam-4                  13.0 ± 0%      13.0 ± 0%    ~     (all equal)
DecoderFactory_SetDecoderFunc-4             16.0 ± 0%      16.0 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                                11.0 ± 0%      11.0 ± 0%    ~     (all equal)
Middleware_control-4                        9.00 ± 0%      9.00 ± 0%    ~     (all equal)
```
</details>

<details><summary>Benchmark result</summary>

```
name                                    time/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4  1.09µs ± 1%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                         511ns ± 0%
DecoderFunc_Decode-4                    1.49µs ± 0%
Decoder_Decode_json-4                   18.2µs ± 1%
Decoder_Decode_queryObject-4            3.90µs ± 0%
Decoder_Decode_jsonParam-4              1.50µs ± 0%
DecoderFactory_SetDecoderFunc-4         1.31µs ± 1%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                            11.4µs ± 0%
Middleware_control-4                    2.58µs ± 2%

name                                    alloc/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4  2.46kB ± 0%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                          440B ± 0%
DecoderFunc_Decode-4                    1.51kB ± 0%
Decoder_Decode_json-4                   12.2kB ± 0%
Decoder_Decode_queryObject-4            2.00kB ± 0%
Decoder_Decode_jsonParam-4                736B ± 0%
DecoderFactory_SetDecoderFunc-4         1.02kB ± 0%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                            1.25kB ± 5%
Middleware_control-4                    11.2kB ± 0%

name                                    allocs/op
pkg:github.com/swaggest/rest/jsonschema goos:linux goarch:amd64
RequestValidator_ValidateRequestData-4    8.00 ± 0%
pkg:github.com/swaggest/rest/request goos:linux goarch:amd64
Decoder_Decode-4                          4.00 ± 0%
DecoderFunc_Decode-4                      12.0 ± 0%
Decoder_Decode_json-4                      177 ± 0%
Decoder_Decode_queryObject-4              36.0 ± 0%
Decoder_Decode_jsonParam-4                13.0 ± 0%
DecoderFactory_SetDecoderFunc-4           16.0 ± 0%
pkg:github.com/swaggest/rest/response/gzip goos:linux goarch:amd64
Middleware-4                              11.0 ± 0%
Middleware_control-4                      9.00 ± 0%
```
</details>
<!-- Sticky Pull Request Commentbench -->
github-actions[bot]: ### Examples Benchmark Result
<details><summary>Benchmark diff with base branch</summary>

```
name                       old time/op    new time/op    delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                16.1µs ± 1%    15.9µs ± 0%    ~     (p=0.286 n=5+4)
_directGzipHead-4            16.0µs ± 2%    15.8µs ± 3%    ~     (p=0.103 n=5+5)
_noDirectGzip-4               102µs ± 1%     102µs ± 1%    ~     (p=0.548 n=5+5)
_directGzip_decode-4          338µs ± 1%     338µs ± 2%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4        103µs ± 0%     103µs ± 1%    ~     (p=0.841 n=5+5)
_jsonBody-4                  33.7µs ± 2%    34.0µs ± 2%    ~     (p=0.151 n=5+5)
_jsonBodyValidation-4        38.5µs ± 1%    38.6µs ± 1%    ~     (p=0.548 n=5+5)
_outputHeaders-4             16.4µs ± 0%    16.6µs ± 1%  +1.18%  (p=0.008 n=5+5)
_requestResponseMapping-4    33.2µs ± 2%    33.2µs ± 2%    ~     (p=0.690 n=5+5)
_validation-4                35.8µs ± 0%    35.6µs ± 1%    ~     (p=0.190 n=4+5)
_noValidation-4              25.0µs ± 1%    25.0µs ± 2%    ~     (p=1.000 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                16.3µs ± 0%    16.1µs ± 0%  -0.77%  (p=0.029 n=4+4)
_directGzipHead-4            16.1µs ± 0%    16.0µs ± 1%  -0.55%  (p=0.032 n=5+5)
_noDirectGzip-4              92.1µs ± 2%    91.5µs ± 1%    ~     (p=0.690 n=5+5)
_directGzip_decode-4          320µs ± 1%     320µs ± 1%    ~     (p=0.841 n=5+5)
_noDirectGzip_decode-4       91.8µs ± 1%    91.7µs ± 0%    ~     (p=0.389 n=5+5)
_htmlResponse-4              29.0µs ± 1%    29.1µs ± 2%    ~     (p=0.841 n=5+5)
_jsonBodyManual-4            20.3µs ± 1%    20.3µs ± 1%    ~     (p=0.548 n=5+5)
_jsonBody-4                  30.3µs ± 1%    30.3µs ± 0%    ~     (p=0.310 n=5+5)
_jsonBodyValidation-4        38.8µs ± 2%    39.1µs ± 0%  +0.91%  (p=0.016 n=5+5)
_outputHeaders-4             28.4µs ± 1%    28.1µs ± 1%    ~     (p=0.056 n=5+5)
_requestResponseMapping-4    33.1µs ± 1%    32.8µs ± 2%    ~     (p=0.095 n=5+5)
_validation-4                35.1µs ± 1%    35.1µs ± 2%    ~     (p=1.000 n=5+5)
_noValidation-4              25.3µs ± 0%    25.1µs ± 1%    ~     (p=0.056 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4               18.3µs ± 1%    18.5µs ± 8%    ~     (p=0.841 n=5+5)
_ok-4                        18.3µs ± 1%    18.1µs ± 1%    ~     (p=0.111 n=5+5)
_invalidBody-4               26.4µs ± 4%    26.1µs ± 5%    ~     (p=0.310 n=5+5)

name                       old 50%:ms     new 50%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                  0.71 ± 4%      0.75 ± 5%  +6.12%  (p=0.016 n=5+5)
_directGzipHead-4              0.71 ± 8%      0.71 ± 4%    ~     (p=1.000 n=5+5)
_noDirectGzip-4                4.66 ± 5%      4.63 ± 3%    ~     (p=1.000 n=5+5)
_directGzip_decode-4           12.7 ± 5%      12.2 ± 8%    ~     (p=0.175 n=5+5)
_noDirectGzip_decode-4         4.62 ± 6%      4.75 ± 6%    ~     (p=0.310 n=5+5)
_jsonBody-4                    1.42 ± 3%      1.43 ± 5%    ~     (p=0.690 n=5+5)
_jsonBodyValidation-4          1.65 ± 6%      1.59 ± 4%    ~     (p=0.151 n=5+5)
_outputHeaders-4               0.73 ± 8%      0.72 ± 4%    ~     (p=0.841 n=5+5)
_requestResponseMapping-4      1.33 ± 7%      1.32 ± 6%    ~     (p=0.690 n=5+5)
_validation-4                  1.47 ± 5%      1.46 ± 5%    ~     (p=0.841 n=5+5)
_noValidation-4                1.03 ± 4%      1.08 ± 5%    ~     (p=0.222 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                  0.74 ± 9%      0.72 ±16%    ~     (p=0.841 n=5+5)
_directGzipHead-4              0.69 ± 5%      0.70 ± 6%    ~     (p=0.841 n=5+5)
_noDirectGzip-4                4.21 ± 5%      4.20 ± 5%    ~     (p=1.000 n=5+5)
_directGzip_decode-4           11.5 ± 5%      11.5 ± 4%    ~     (p=0.794 n=5+5)
_noDirectGzip_decode-4         4.11 ± 3%      4.14 ± 2%    ~     (p=0.794 n=5+5)
_htmlResponse-4                1.23 ± 5%      1.25 ± 6%    ~     (p=0.548 n=5+5)
_jsonBodyManual-4              0.89 ± 5%      0.89 ± 4%    ~     (p=1.000 n=5+5)
_jsonBody-4                    1.30 ± 7%      1.23 ± 3%    ~     (p=0.056 n=5+5)
_jsonBodyValidation-4          1.55 ± 8%      1.57 ±10%    ~     (p=0.841 n=5+5)
_outputHeaders-4               1.16 ± 6%      1.14 ± 5%    ~     (p=0.460 n=5+5)
_requestResponseMapping-4      1.37 ± 3%      1.31 ± 9%    ~     (p=0.222 n=5+5)
_validation-4                  1.43 ± 4%      1.39 ± 2%    ~     (p=0.222 n=5+5)
_noValidation-4                1.09 ± 7%      1.05 ± 4%    ~     (p=0.151 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 0.82 ± 9%      0.83 ± 7%    ~     (p=0.841 n=5+5)
_ok-4                          0.79 ± 7%      0.81 ± 8%    ~     (p=0.548 n=5+5)
_invalidBody-4                 1.08 ± 7%      1.12 ± 8%    ~     (p=0.595 n=5+5)

name                       old 90%:ms     new 90%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                  1.46 ± 7%      1.48 ±11%    ~     (p=0.841 n=5+5)
_directGzipHead-4              1.44 ± 5%      1.41 ± 2%    ~     (p=0.460 n=5+5)
_noDirectGzip-4                9.79 ± 5%      9.62 ± 8%    ~     (p=0.421 n=5+5)
_directGzip_decode-4           30.9 ± 4%      32.1 ± 3%  +4.12%  (p=0.032 n=5+5)
_noDirectGzip_decode-4         9.75 ± 5%      9.81 ± 3%    ~     (p=0.690 n=5+5)
_jsonBody-4                    3.08 ± 4%      3.25 ± 5%    ~     (p=0.056 n=5+5)
_jsonBodyValidation-4          3.61 ± 6%      3.52 ± 5%    ~     (p=0.421 n=5+5)
_outputHeaders-4               1.47 ± 7%      1.46 ± 4%    ~     (p=0.889 n=5+5)
_requestResponseMapping-4      3.09 ± 3%      3.08 ± 5%    ~     (p=0.889 n=5+5)
_validation-4                  3.38 ± 9%      3.31 ± 7%    ~     (p=0.548 n=5+5)
_noValidation-4                2.34 ± 3%      2.31 ± 4%    ~     (p=0.690 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                  1.49 ± 4%      1.46 ± 6%    ~     (p=0.167 n=5+5)
_directGzipHead-4              1.47 ± 7%      1.45 ± 5%    ~     (p=0.690 n=5+5)
_noDirectGzip-4                8.76 ± 3%      8.70 ± 2%    ~     (p=0.690 n=5+5)
_directGzip_decode-4           30.1 ± 6%      30.0 ± 6%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4         8.70 ± 3%      8.80 ± 6%    ~     (p=0.841 n=5+5)
_htmlResponse-4                2.68 ± 4%      2.85 ± 3%  +6.41%  (p=0.008 n=5+5)
_jsonBodyManual-4              1.79 ± 5%      1.84 ± 4%    ~     (p=0.056 n=5+5)
_jsonBody-4                    2.78 ± 5%      2.77 ± 5%    ~     (p=0.841 n=5+5)
_jsonBodyValidation-4          3.58 ± 5%      3.63 ± 3%    ~     (p=0.421 n=5+5)
_outputHeaders-4               2.68 ± 2%      2.71 ± 3%    ~     (p=1.000 n=5+5)
_requestResponseMapping-4      3.14 ± 4%      3.12 ± 4%    ~     (p=1.000 n=5+5)
_validation-4                  3.31 ± 7%      3.31 ± 5%    ~     (p=0.548 n=5+5)
_noValidation-4                2.40 ± 3%      2.35 ± 5%    ~     (p=0.421 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 1.62 ± 4%      1.69 ± 6%    ~     (p=0.222 n=5+5)
_ok-4                          1.64 ± 8%      1.69 ± 6%    ~     (p=0.310 n=5+5)
_invalidBody-4                 2.45 ± 6%      2.47 ± 8%    ~     (p=1.000 n=5+5)

name                       old 99%:ms     new 99%:ms     delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                  2.40 ± 8%      2.48 ±18%    ~     (p=0.841 n=5+5)
_directGzipHead-4              2.40 ± 7%      2.42 ± 8%    ~     (p=0.841 n=5+5)
_noDirectGzip-4                14.8 ± 6%      14.9 ± 5%    ~     (p=1.000 n=5+5)
_directGzip_decode-4           57.8 ± 6%      59.6 ± 5%    ~     (p=0.310 n=5+5)
_noDirectGzip_decode-4         15.1 ± 8%      15.1 ± 5%    ~     (p=1.000 n=5+5)
_jsonBody-4                    4.96 ± 7%      5.25 ±10%    ~     (p=0.095 n=5+5)
_jsonBodyValidation-4          5.80 ± 9%      5.81 ± 9%    ~     (p=0.841 n=5+5)
_outputHeaders-4               2.49 ± 5%      2.56 ± 5%    ~     (p=0.421 n=5+5)
_requestResponseMapping-4      5.46 ± 8%      5.55 ±14%    ~     (p=0.841 n=5+5)
_validation-4                  6.26 ± 9%      5.86 ±16%    ~     (p=0.151 n=5+5)
_noValidation-4                4.44 ± 3%      4.36 ±17%    ~     (p=0.548 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                  2.62 ±24%      2.51 ±27%    ~     (p=0.151 n=5+5)
_directGzipHead-4              2.36 ± 4%      2.40 ± 6%    ~     (p=0.548 n=5+5)
_noDirectGzip-4                13.6 ±11%      13.2 ± 4%    ~     (p=0.690 n=5+5)
_directGzip_decode-4           56.4 ± 9%      55.9 ±10%    ~     (p=0.690 n=5+5)
_noDirectGzip_decode-4         13.3 ± 5%      13.2 ± 3%    ~     (p=0.690 n=5+5)
_htmlResponse-4                4.56 ± 4%      4.77 ±10%    ~     (p=0.548 n=5+5)
_jsonBodyManual-4              3.11 ± 4%      3.08 ± 7%    ~     (p=0.841 n=5+5)
_jsonBody-4                    5.16 ± 8%      5.26 ± 6%    ~     (p=0.548 n=5+5)
_jsonBodyValidation-4          6.11 ±14%      6.88 ± 8%    ~     (p=0.056 n=5+5)
_outputHeaders-4               4.84 ± 3%      4.81 ± 8%    ~     (p=0.690 n=5+5)
_requestResponseMapping-4      5.42 ± 7%      5.17 ± 7%    ~     (p=0.222 n=5+5)
_validation-4                  5.36 ± 7%      5.44 ± 8%    ~     (p=0.548 n=5+5)
_noValidation-4                4.03 ± 7%      3.92 ± 2%    ~     (p=0.310 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 2.62 ± 3%      2.77 ±22%    ~     (p=0.841 n=5+5)
_ok-4                          2.70 ± 6%      2.66 ± 3%    ~     (p=0.690 n=5+5)
_invalidBody-4                 4.55 ± 4%      4.23 ± 8%    ~     (p=0.056 n=5+5)

name                       old 99.9%:ms   new 99.9%:ms   delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                  4.38 ±13%      4.86 ±92%    ~     (p=0.421 n=5+5)
_directGzipHead-4              4.90 ±27%      4.41 ±39%    ~     (p=0.548 n=5+5)
_noDirectGzip-4                19.5 ± 7%      19.3 ± 8%    ~     (p=0.794 n=5+5)
_directGzip_decode-4           78.2 ±18%      77.7 ±16%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4         20.1 ± 6%      20.2 ±12%    ~     (p=1.000 n=5+5)
_jsonBody-4                    8.69 ±24%      8.14 ± 1%    ~     (p=0.730 n=5+4)
_jsonBodyValidation-4          9.04 ±14%      8.80 ±23%    ~     (p=0.548 n=5+5)
_outputHeaders-4               4.78 ± 7%      5.20 ±38%    ~     (p=0.841 n=5+5)
_requestResponseMapping-4      8.83 ± 8%      9.00 ±12%    ~     (p=0.841 n=5+5)
_validation-4                  9.94 ± 9%     10.04 ±10%    ~     (p=0.841 n=5+5)
_noValidation-4                7.30 ± 2%      8.26 ±24%    ~     (p=0.151 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                  3.83 ±15%      3.87 ±13%    ~     (p=0.886 n=4+4)
_directGzipHead-4              4.61 ±20%      4.26 ±34%    ~     (p=0.548 n=5+5)
_noDirectGzip-4                19.4 ±53%      16.6 ±13%    ~     (p=0.690 n=5+5)
_directGzip_decode-4           74.8 ± 6%      73.5 ±19%    ~     (p=0.548 n=5+5)
_noDirectGzip_decode-4         17.9 ± 4%      17.7 ±13%    ~     (p=0.516 n=5+5)
_htmlResponse-4                8.04 ±32%      8.24 ±11%    ~     (p=0.421 n=5+5)
_jsonBodyManual-4              6.05 ±12%      6.00 ± 8%    ~     (p=1.000 n=5+5)
_jsonBody-4                    9.04 ±11%      7.70 ±20%    ~     (p=0.056 n=5+5)
_jsonBodyValidation-4          10.1 ±18%      10.6 ±13%    ~     (p=0.690 n=5+5)
_outputHeaders-4               8.16 ±13%      7.87 ±24%    ~     (p=0.690 n=5+5)
_requestResponseMapping-4      8.29 ±23%      8.46 ± 8%    ~     (p=0.421 n=5+5)
_validation-4                  8.40 ±13%      8.72 ±17%    ~     (p=0.841 n=5+5)
_noValidation-4                6.14 ±10%      6.28 ±33%    ~     (p=0.841 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 4.01 ±35%      5.67 ±83%    ~     (p=0.222 n=5+5)
_ok-4                          4.58 ±27%      4.41 ±13%    ~     (p=1.000 n=5+5)
_invalidBody-4                 6.72 ±21%      6.34 ±13%    ~     (p=0.548 n=5+5)

name                       old B:rcvd/op  new B:rcvd/op  delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                   630 ± 0%       630 ± 0%    ~     (all equal)
_directGzipHead-4               174 ± 0%       174 ± 0%    ~     (all equal)
_noDirectGzip-4               1.03k ± 0%     1.03k ± 0%    ~     (all equal)
_directGzip_decode-4            630 ± 0%       630 ± 0%    ~     (all equal)
_noDirectGzip_decode-4        1.03k ± 0%     1.03k ± 0%    ~     (all equal)
_jsonBody-4                     199 ± 0%       199 ± 0%    ~     (all equal)
_jsonBodyValidation-4           185 ± 0%       185 ± 0%    ~     (all equal)
_outputHeaders-4                146 ± 0%       146 ± 0%    ~     (all equal)
_requestResponseMapping-4      94.0 ± 0%      94.0 ± 0%    ~     (all equal)
_validation-4                   168 ± 0%       168 ± 0%    ~     (all equal)
_noValidation-4                 168 ± 0%       168 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                   638 ± 0%       638 ± 0%    ~     (all equal)
_directGzipHead-4               182 ± 0%       182 ± 0%    ~     (all equal)
_noDirectGzip-4               1.04k ± 0%     1.04k ± 0%    ~     (all equal)
_directGzip_decode-4            638 ± 0%       638 ± 0%    ~     (all equal)
_noDirectGzip_decode-4        1.04k ± 0%     1.04k ± 0%    ~     (all equal)
_htmlResponse-4                 355 ± 0%       355 ± 0%    ~     (all equal)
_jsonBodyManual-4               207 ± 0%       207 ± 0%    ~     (all equal)
_jsonBody-4                     207 ± 0%       207 ± 0%    ~     (all equal)
_jsonBodyValidation-4           193 ± 0%       193 ± 0%    ~     (all equal)
_outputHeaders-4                214 ± 0%       214 ± 0%    ~     (all equal)
_requestResponseMapping-4       108 ± 0%       108 ± 0%    ~     (all equal)
_validation-4                   176 ± 0%       176 ± 0%    ~     (all equal)
_noValidation-4                 176 ± 0%       176 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                  322 ± 0%       322 ± 0%    ~     (all equal)
_ok-4                           344 ± 0%       344 ± 0%    ~     (all equal)
_invalidBody-4                  420 ± 0%       420 ± 0%    ~     (all equal)

name                       old B:sent/op  new B:sent/op  delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                   103 ± 0%       103 ± 0%    ~     (all equal)
_directGzipHead-4               104 ± 0%       104 ± 0%    ~     (all equal)
_noDirectGzip-4                 117 ± 0%       117 ± 0%    ~     (all equal)
_directGzip_decode-4            116 ± 0%       116 ± 0%    ~     (all equal)
_noDirectGzip_decode-4          130 ± 0%       130 ± 0%    ~     (all equal)
_jsonBody-4                     188 ± 0%       188 ± 0%    ~     (all equal)
_jsonBodyValidation-4           192 ± 0%       192 ± 0%    ~     (all equal)
_outputHeaders-4               77.0 ± 0%      77.0 ± 0%    ~     (all equal)
_requestResponseMapping-4       169 ± 0%       169 ± 0%    ~     (all equal)
_validation-4                   170 ± 0%       170 ± 0%    ~     (all equal)
_noValidation-4                 173 ± 0%       173 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                   103 ± 0%       103 ± 0%    ~     (all equal)
_directGzipHead-4               104 ± 0%       104 ± 0%    ~     (all equal)
_noDirectGzip-4                 117 ± 0%       117 ± 0%    ~     (all equal)
_directGzip_decode-4            116 ± 0%       116 ± 0%    ~     (all equal)
_noDirectGzip_decode-4          130 ± 0%       130 ± 0%    ~     (all equal)
_htmlResponse-4                 108 ± 0%       108 ± 0%    ~     (all equal)
_jsonBodyManual-4               195 ± 0%       195 ± 0%    ~     (all equal)
_jsonBody-4                     188 ± 0%       188 ± 0%    ~     (all equal)
_jsonBodyValidation-4           192 ± 0%       192 ± 0%    ~     (all equal)
_outputHeaders-4               88.0 ± 0%      88.0 ± 0%    ~     (all equal)
_requestResponseMapping-4       169 ± 0%       169 ± 0%    ~     (all equal)
_validation-4                   170 ± 0%       170 ± 0%    ~     (all equal)
_noValidation-4                 173 ± 0%       173 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 74.0 ± 0%      74.0 ± 0%    ~     (all equal)
_ok-4                          74.0 ± 0%      74.0 ± 0%    ~     (all equal)
_invalidBody-4                  137 ± 0%       137 ± 0%    ~     (all equal)

name                       old rps        new rps        delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                 62.3k ± 1%     62.8k ± 0%    ~     (p=0.286 n=5+4)
_directGzipHead-4             62.4k ± 2%     63.3k ± 3%    ~     (p=0.151 n=5+5)
_noDirectGzip-4               9.77k ± 1%     9.81k ± 1%    ~     (p=0.421 n=5+5)
_directGzip_decode-4          2.96k ± 1%     2.96k ± 2%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4        9.70k ± 0%     9.69k ± 1%    ~     (p=0.738 n=5+5)
_jsonBody-4                   29.7k ± 2%     29.4k ± 2%    ~     (p=0.151 n=5+5)
_jsonBodyValidation-4         26.0k ± 1%     25.9k ± 1%    ~     (p=0.548 n=5+5)
_outputHeaders-4              61.1k ± 0%     60.4k ± 1%  -1.16%  (p=0.008 n=5+5)
_requestResponseMapping-4     30.1k ± 2%     30.1k ± 2%    ~     (p=0.690 n=5+5)
_validation-4                 27.9k ± 0%     28.1k ± 1%    ~     (p=0.190 n=4+5)
_noValidation-4               40.0k ± 1%     39.9k ± 2%    ~     (p=1.000 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                 61.5k ± 0%     62.0k ± 0%  +0.77%  (p=0.029 n=4+4)
_directGzipHead-4             62.2k ± 0%     62.5k ± 1%  +0.56%  (p=0.032 n=5+5)
_noDirectGzip-4               10.9k ± 2%     10.9k ± 1%    ~     (p=0.690 n=5+5)
_directGzip_decode-4          3.12k ± 1%     3.12k ± 1%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4        10.9k ± 1%     10.9k ± 0%    ~     (p=0.389 n=5+5)
_htmlResponse-4               34.5k ± 1%     34.4k ± 2%    ~     (p=0.841 n=5+5)
_jsonBodyManual-4             49.3k ± 1%     49.2k ± 1%    ~     (p=0.548 n=5+5)
_jsonBody-4                   33.0k ± 1%     33.0k ± 0%    ~     (p=0.310 n=5+5)
_jsonBodyValidation-4         25.8k ± 2%     25.6k ± 0%  -0.91%  (p=0.016 n=5+5)
_outputHeaders-4              35.2k ± 1%     35.6k ± 1%    ~     (p=0.056 n=5+5)
_requestResponseMapping-4     30.2k ± 1%     30.5k ± 2%    ~     (p=0.095 n=5+5)
_validation-4                 28.5k ± 1%     28.5k ± 2%    ~     (p=1.000 n=5+5)
_noValidation-4               39.6k ± 0%     39.9k ± 1%    ~     (p=0.056 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                54.8k ± 1%     54.1k ± 7%    ~     (p=0.841 n=5+5)
_ok-4                         54.8k ± 1%     55.2k ± 1%    ~     (p=0.095 n=5+5)
_invalidBody-4                37.8k ± 4%     38.3k ± 4%    ~     (p=0.310 n=5+5)

name                       old alloc/op   new alloc/op   delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                3.85kB ± 0%    3.85kB ± 0%    ~     (p=0.825 n=5+5)
_directGzipHead-4            3.85kB ± 0%    3.85kB ± 0%    ~     (p=1.000 n=5+5)
_noDirectGzip-4              6.74kB ±22%    6.50kB ±18%    ~     (p=0.548 n=5+5)
_directGzip_decode-4          404kB ± 0%     404kB ± 0%    ~     (p=0.151 n=5+5)
_noDirectGzip_decode-4       5.97kB ± 3%    5.86kB ± 6%    ~     (p=0.548 n=5+5)
_jsonBody-4                  13.2kB ± 0%    13.2kB ± 0%    ~     (p=0.730 n=5+5)
_jsonBodyValidation-4        19.0kB ± 0%    19.0kB ± 0%    ~     (p=1.000 n=5+5)
_outputHeaders-4             3.57kB ± 0%    3.57kB ± 0%    ~     (p=0.444 n=5+5)
_requestResponseMapping-4    16.7kB ± 0%    16.7kB ± 0%  -0.05%  (p=0.024 n=5+5)
_validation-4                16.6kB ± 0%    16.6kB ± 0%    ~     (p=0.151 n=5+5)
_noValidation-4              7.77kB ± 0%    7.78kB ± 0%    ~     (p=0.421 n=5+5)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                3.89kB ± 0%    3.89kB ± 0%    ~     (p=0.786 n=5+5)
_directGzipHead-4            3.88kB ± 0%    3.88kB ± 0%    ~     (p=0.873 n=5+5)
_noDirectGzip-4              6.49kB ±22%    6.72kB ±23%    ~     (p=0.690 n=5+5)
_directGzip_decode-4          404kB ± 0%     404kB ± 0%    ~     (p=1.000 n=5+5)
_noDirectGzip_decode-4       6.14kB ± 3%    6.16kB ±10%    ~     (p=0.690 n=5+5)
_htmlResponse-4              8.08kB ± 0%    8.08kB ± 0%    ~     (p=0.587 n=5+5)
_jsonBodyManual-4            4.50kB ± 0%    4.50kB ± 0%    ~     (p=0.659 n=5+5)
_jsonBody-4                  10.3kB ± 0%    10.3kB ± 0%    ~     (p=0.603 n=5+5)
_jsonBodyValidation-4        19.1kB ± 0%    19.1kB ± 0%    ~     (p=0.532 n=5+5)
_outputHeaders-4             10.4kB ± 0%    10.4kB ± 0%    ~     (p=0.889 n=5+5)
_requestResponseMapping-4    16.7kB ± 0%    16.7kB ± 0%    ~     (p=0.214 n=5+5)
_validation-4                16.6kB ± 0%    16.6kB ± 0%    ~     (p=0.889 n=5+5)
_noValidation-4              7.84kB ± 0%    7.83kB ± 0%    ~     (p=0.317 n=5+5)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4               4.65kB ± 0%    4.65kB ± 0%    ~     (p=0.873 n=5+5)
_ok-4                        4.56kB ± 0%    4.55kB ± 0%    ~     (p=0.540 n=5+4)
_invalidBody-4               8.27kB ± 0%    8.27kB ± 0%    ~     (p=0.657 n=4+4)

name                       old allocs/op  new allocs/op  delta
pkg:github.com/swaggest/rest/_examples/advanced goos:linux goarch:amd64
_directGzip-4                  42.0 ± 0%      42.0 ± 0%    ~     (all equal)
_directGzipHead-4              42.0 ± 0%      42.0 ± 0%    ~     (all equal)
_noDirectGzip-4                49.2 ± 4%      49.2 ± 4%    ~     (p=1.000 n=5+5)
_directGzip_decode-4            503 ± 0%       503 ± 0%    ~     (p=0.238 n=5+5)
_noDirectGzip_decode-4         50.0 ± 0%      50.0 ± 0%    ~     (all equal)
_jsonBody-4                     128 ± 0%       128 ± 0%    ~     (all equal)
_jsonBodyValidation-4           186 ± 0%       186 ± 0%    ~     (all equal)
_outputHeaders-4               36.0 ± 0%      36.0 ± 0%    ~     (all equal)
_requestResponseMapping-4       124 ± 0%       124 ± 0%    ~     (all equal)
_validation-4                   155 ± 0%       154 ± 0%  -0.65%  (p=0.029 n=4+4)
_noValidation-4                91.0 ± 0%      91.0 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/advanced-generic-openapi31 goos:linux goarch:amd64
_directGzip-4                  44.0 ± 0%      44.0 ± 0%    ~     (all equal)
_directGzipHead-4              44.0 ± 0%      44.0 ± 0%    ~     (all equal)
_noDirectGzip-4                51.2 ± 4%      51.2 ± 4%    ~     (p=1.000 n=5+5)
_directGzip_decode-4            505 ± 0%       505 ± 0%    ~     (p=0.643 n=5+5)
_noDirectGzip_decode-4         52.0 ± 0%      52.0 ± 0%    ~     (all equal)
_htmlResponse-4                 145 ± 0%       145 ± 0%    ~     (all equal)
_jsonBodyManual-4              49.0 ± 0%      49.0 ± 0%    ~     (all equal)
_jsonBody-4                     100 ± 0%       100 ± 0%    ~     (all equal)
_jsonBodyValidation-4           188 ± 0%       188 ± 0%    ~     (all equal)
_outputHeaders-4                113 ± 0%       113 ± 0%    ~     (all equal)
_requestResponseMapping-4       126 ± 0%       126 ± 0%    ~     (all equal)
_validation-4                   156 ± 0%       156 ± 0%    ~     (all equal)
_noValidation-4                93.0 ± 0%      93.0 ± 0%    ~     (all equal)
pkg:github.com/swaggest/rest/_examples/task-api/internal/infra/nethttp goos:linux goarch:amd64
_notFoundSrv-4                 53.0 ± 0%      53.0 ± 0%    ~     (all equal)
_ok-4                          49.0 ± 0%      49.0 ± 0%    ~     (all equal)
_invalidBody-4                 97.0 ± 0%      97.0 ± 0%    ~     (all equal)
```
</details>
<!-- Sticky Pull Request Commentbench-examples -->

Patch:
diff --git a/chirouter/wrapper.go b/chirouter/wrapper.go
index 47e0361..5fe11ce 100644
--- a/chirouter/wrapper.go
+++ b/chirouter/wrapper.go
@@ -199,6 +199,15 @@ func (r *Wrapper) Trace(pattern string, handlerFn http.HandlerFunc) {
 	r.Method(http.MethodTrace, pattern, handlerFn)
 }
 
+// HandlerFunc prepares handler and returns its function.
+//
+// Can be used as input for NotFound, MethodNotAllowed.
+func (r *Wrapper) HandlerFunc(h http.Handler) http.HandlerFunc {
+	h = nethttp.WrapHandler(h, r.wraps...)
+
+	return h.ServeHTTP
+}
+
 func (r *Wrapper) resolvePattern(pattern string) string {
 	return r.basePattern + strings.ReplaceAll(pattern, "/*/", "/")
 }
diff --git a/request/middleware.go b/request/middleware.go
index 96533bd..4d53d15 100644
--- a/request/middleware.go
+++ b/request/middleware.go
@@ -32,7 +32,6 @@ func DecoderMiddleware(factory DecoderMaker) func(http.Handler) http.Handler {
 		)
 
 		if !nethttp.HandlerAs(handler, &setRequestDecoder) ||
-			!nethttp.HandlerAs(handler, &withRoute) ||
 			!nethttp.HandlerAs(handler, &withUseCase) ||
 			!usecase.As(withUseCase.UseCase(), &useCaseWithInput) {
 			return handler
@@ -45,7 +44,11 @@ func DecoderMiddleware(factory DecoderMaker) func(http.Handler) http.Handler {
 
 		input := useCaseWithInput.InputPort()
 		if input != nil {
-			method := withRoute.RouteMethod()
+			method := http.MethodPost // Default for handlers without method (for example NotFound handler).
+			if nethttp.HandlerAs(handler, &withRoute) {
+				method = withRoute.RouteMethod()
+			}
+
 			dec := factory.MakeDecoder(method, input, customMapping)
 			setRequestDecoder.SetRequestDecoder(dec)
 		}
diff --git a/response/encoder.go b/response/encoder.go
index 875fde7..f34a8bb 100644
--- a/response/encoder.go
+++ b/response/encoder.go
@@ -17,6 +17,15 @@ import (
 	"github.com/swaggest/usecase/status"
 )
 
+type (
+	// Setter captures original http.ResponseWriter.
+	//
+	// Implement this interface on a pointer to your output structure to get access to http.ResponseWriter.
+	Setter interface {
+		SetResponseWriter(rw http.ResponseWriter)
+	}
+)
+
 // Encoder prepares and writes http response.
 type Encoder struct {
 	JSONWriter func(v interface{})
@@ -30,6 +39,7 @@ type Encoder struct {
 	unwrapInterface      bool
 
 	dynamicWithHeadersSetup bool
+	dynamicSetter           bool
 	dynamicETagged          bool
 	dynamicNoContent        bool
 }
@@ -187,6 +197,10 @@ func (h *Encoder) SetupOutput(output interface{}, ht *rest.HandlerTrait) {
 		h.dynamicWithHeadersSetup = true
 	}
 
+	if _, ok := output.(Setter); ok || h.unwrapInterface {
+		h.dynamicSetter = true
+	}
+
 	if _, ok := output.(rest.ETagged); ok || h.unwrapInterface {
 		h.dynamicETagged = true
 	}
@@ -504,6 +518,12 @@ func (h *Encoder) MakeOutput(w http.ResponseWriter, ht rest.HandlerTrait) interf
 		}
 	}
 
+	if h.dynamicSetter {
+		if setter, ok := output.(Setter); ok {
+			setter.SetResponseWriter(w)
+		}
+	}
+
 	return output
 }
 
@@ -550,3 +570,18 @@ func (w *writerWithHeaders) Write(data []byte) (int, error) {
 
 	return w.ResponseWriter.Write(data)
 }
+
+// EmbeddedSetter can capture http.ResponseWriter in your output structure.
+type EmbeddedSetter struct {
+	rw http.ResponseWriter
+}
+
+// SetResponseWriter implements Setter.
+func (e *EmbeddedSetter) SetResponseWriter(rw http.ResponseWriter) {
+	e.rw = rw
+}
+
+// ResponseWriter is an accessor.
+func (e *EmbeddedSetter) ResponseWriter() http.ResponseWriter {
+	return e.rw
+}
diff --git a/web/service.go b/web/service.go
index fed0621..d907caa 100644
--- a/web/service.go
+++ b/web/service.go
@@ -162,6 +162,16 @@ func (s *Service) Trace(pattern string, uc usecase.Interactor, options ...func(h
 	s.Method(http.MethodTrace, pattern, nethttp.NewHandler(uc, options...))
 }
 
+// OnNotFound registers usecase interactor as a handler for not found conditions.
+func (s *Service) OnNotFound(uc usecase.Interactor, options ...func(h *nethttp.Handler)) {
+	s.NotFound(s.HandlerFunc(nethttp.NewHandler(uc, options...)))
+}
+
+// OnMethodNotAllowed registers usecase interactor as a handler for method not allowed conditions.
+func (s *Service) OnMethodNotAllowed(uc usecase.Interactor, options ...func(h *nethttp.Handler)) {
+	s.MethodNotAllowed(s.HandlerFunc(nethttp.NewHandler(uc, options...)))
+}
+
 // Docs adds the route `pattern` that serves API documentation with Swagger UI.
 //
 // Swagger UI should be provided by `swgui` handler constructor, you can use one of these functions


Test patch:
diff --git a/chirouter/wrapper_test.go b/chirouter/wrapper_test.go
index c23a545..0ff0d39 100644
--- a/chirouter/wrapper_test.go
+++ b/chirouter/wrapper_test.go
@@ -51,7 +51,8 @@ func (h HandlerWithBar) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
 }
 
 func TestNewWrapper(t *testing.T) {
-	r := chirouter.NewWrapper(chi.NewRouter()).With(func(handler http.Handler) http.Handler {
+	w := chirouter.NewWrapper(chi.NewRouter())
+	r := w.With(func(handler http.Handler) http.Handler {
 		return http.HandlerFunc(handler.ServeHTTP)
 	})
 
@@ -79,6 +80,8 @@ func TestNewWrapper(t *testing.T) {
 
 	r.Use(mw)
 
+	r.NotFound(r.(*chirouter.Wrapper).HandlerFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})))
+
 	r.Group(func(r chi.Router) {
 		r.Method(http.MethodPost,
 			"/baz/{id}/",
@@ -125,7 +128,7 @@ func TestNewWrapper(t *testing.T) {
 	}
 
 	assert.Equal(t, 14, handlersCnt)
-	assert.Equal(t, 21, totalCnt)
+	assert.Equal(t, 22, totalCnt)
 }
 
 func TestWrapper_Use_precedence(t *testing.T) {
diff --git a/response/encoder_test.go b/response/encoder_test.go
index 6f16960..93d530f 100644
--- a/response/encoder_test.go
+++ b/response/encoder_test.go
@@ -236,3 +236,67 @@ func TestEncoder_Writer_httpStatus(t *testing.T) {
 	e.WriteSuccessfulResponse(w, r, output, rest.HandlerTrait{})
 	assert.Equal(t, http.StatusCreated, w.Code)
 }
+
+func TestEmbeddedSetter_SetResponseWriter(t *testing.T) {
+	e := response.Encoder{}
+
+	type EmbeddedHeader struct {
+		Foo int    `header:"X-Foo" json:"-"`
+		Bar string `cookie:"bar" json:"-"`
+	}
+
+	type outputPort struct {
+		response.EmbeddedSetter
+		EmbeddedHeader
+		Name    string   `header:"X-Name" json:"-"`
+		Items   []string `json:"items"`
+		Cookie  int      `cookie:"coo,httponly,path=/foo" json:"-"`
+		Cookie2 bool     `cookie:"coo2,httponly,secure,samesite=lax,path=/foo,max-age=86400" json:"-"`
+	}
+
+	ht := rest.HandlerTrait{
+		SuccessContentType: "application/x-vnd-json",
+	}
+
+	validator := jsonschema.Validator{}
+	require.NoError(t, validator.AddSchema(
+		rest.ParamInHeader,
+		"X-Name",
+		[]byte(`{"type":"string","minLength":3}`),
+		false),
+	)
+
+	ht.RespValidator = &validator
+
+	e.SetupOutput(outputPort{}, &ht)
+
+	r, err := http.NewRequest(http.MethodGet, "/", nil)
+	require.NoError(t, err)
+
+	w := httptest.NewRecorder()
+	output := e.MakeOutput(w, ht)
+
+	out, ok := output.(*outputPort)
+	assert.True(t, ok)
+
+	out.Foo = 321
+	out.Bar = "baz"
+	out.Name = "Jane"
+	out.Items = []string{"one", "two", "three"}
+	out.Cookie = 123
+	out.Cookie2 = true
+
+	e.WriteSuccessfulResponse(w, r, output, ht)
+	assert.Equal(t, http.StatusOK, w.Code)
+	assert.Equal(t, "Jane", w.Header().Get("X-Name"))
+	assert.Equal(t, "321", w.Header().Get("X-Foo"))
+	assert.Equal(t, []string{
+		"bar=baz",
+		"coo=123; Path=/foo; HttpOnly",
+		"coo2=true; Path=/foo; Max-Age=86400; HttpOnly; Secure; SameSite=Lax",
+	}, w.Header()["Set-Cookie"])
+	assert.Equal(t, "application/x-vnd-json", w.Header().Get("Content-Type"))
+	assert.Equal(t, "32", w.Header().Get("Content-Length"))
+	assert.Equal(t, `{"items":["one","two","three"]}`+"\n", w.Body.String())
+	assert.Equal(t, w, out.ResponseWriter())
+}
diff --git a/web/service_test.go b/web/service_test.go
index 6b57a9c..1d822cf 100644
--- a/web/service_test.go
+++ b/web/service_test.go
@@ -56,6 +56,26 @@ func TestDefaultService(t *testing.T) {
 		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {})
 	})
 
+	service.OnNotFound(usecase.NewIOI(
+		nil,
+		new(struct {
+			Foo string `json:"foo"`
+		}),
+		func(ctx context.Context, input, output interface{}) error {
+			return nil
+		}),
+	)
+
+	service.OnMethodNotAllowed(usecase.NewIOI(
+		nil,
+		new(struct {
+			Foo string `json:"foo"`
+		}),
+		func(ctx context.Context, input, output interface{}) error {
+			return nil
+		}),
+	)
+
 	rw := httptest.NewRecorder()
 	r, err := http.NewRequest(http.MethodGet, "http://localhost/docs/openapi.json", nil)
 	require.NoError(t, err)